From c0cd1408ada17e30c52d4ba58b93b906987fa5e2 Mon Sep 17 00:00:00 2001 From: roost-io Date: Wed, 3 Dec 2025 14:49:23 +0000 Subject: [PATCH] Add API Tests (Pytest Framework, Open AI) generated by RoostGPT Using AI Model gpt-4o --- Roost-README.md | 25 + requirements-roost.txt | 2 + tests/CIRCLECI_API/api.json | 23564 ++++++++++++++++ tests/CIRCLECI_API/config.yml | 55 + tests/CIRCLECI_API/conftest.py | 84 + tests/CIRCLECI_API/context.json | 50 + tests/CIRCLECI_API/context_context_id.json | 37 + ...ntext_context_id_environment-variable.json | 38 + ...xt_id_environment-variable_env_var_na.json | 38 + .../context_context_id_restrictions.json | 31 + ...ontext_id_restrictions_restriction_id.json | 32 + tests/CIRCLECI_API/deploy_components.json | 47 + .../deploy_components_component_id.json | 27 + ...ploy_components_component_id_versions.json | 37 + tests/CIRCLECI_API/deploy_environments.json | 39 + .../deploy_environments_environment_id.json | 27 + .../insights_org-slug_summary.json | 44 + .../insights_pages_project-slug_summary.json | 51 + .../insights_project-slug_branches.json | 30 + .../insights_project-slug_flaky-tests.json | 27 + .../insights_project-slug_workflows.json | 42 + ..._project-slug_workflows_workflow-name.json | 38 + ...ect-slug_workflows_workflow-name_jobs.json | 37 + ...ect-slug_workflows_workflow-name_summ.json | 35 + ...ect-slug_workflows_workflow-name_test.json | 35 + ...-series_project-slug_workflows_workfl.json | 47 + tests/CIRCLECI_API/jobs_job-id_cancel.json | 42 + tests/CIRCLECI_API/me.json | 40 + tests/CIRCLECI_API/me_collaborations.json | 54 + .../org_orgID_oidc-custom-claims.json | 60 + ..._project_projectID_oidc-custom-claims.json | 77 + tests/CIRCLECI_API/organization.json | 30 + .../organization_org-slug-or-id.json | 26 + .../organization_org-slug-or-id_project.json | 31 + ...ion_org-slug-or-id_url-orb-allow-list.json | 27 + ...org-slug-or-id_url-orb-allow-list_all.json | 30 + .../organizations_org_id_groups.json | 31 + .../organizations_org_id_groups_group_id.json | 27 + ...organizations_org_id_usage_export_job.json | 38 + ..._org_id_usage_export_job_usage_export.json | 66 + ...wner_ownerID_context_context_decision.json | 77 + ...D_context_context_decision_decisionID.json | 43 + ..._context_context_decision_decisionID_.json | 43 + ...rID_context_context_decision_settings.json | 56 + ...ownerID_context_context_policy-bundle.json | 74 + ..._context_context_policy-bundle_policy.json | 43 + tests/CIRCLECI_API/pipeline.json | 33 + tests/CIRCLECI_API/pipeline_continue.json | 39 + tests/CIRCLECI_API/pipeline_pipeline-id.json | 27 + .../pipeline_pipeline-id_config.json | 27 + .../pipeline_pipeline-id_values.json | 27 + .../pipeline_pipeline-id_workflow.json | 29 + tests/CIRCLECI_API/project_project-slug.json | 27 + .../project_project-slug_checkout-key.json | 31 + ...project-slug_checkout-key_fingerprint.json | 31 + .../project_project-slug_envvar.json | 35 + .../project_project-slug_envvar_name.json | 31 + ...ect_project-slug_job-number_artifacts.json | 31 + ...project_project-slug_job-number_tests.json | 31 + .../project_project-slug_job_job-number.json | 31 + ...ct_project-slug_job_job-number_cancel.json | 31 + .../project_project-slug_pipeline.json | 30 + .../project_project-slug_pipeline_mine.json | 30 + ...project-slug_pipeline_pipeline-number.json | 31 + .../project_project-slug_schedule.json | 29 + ...project_provider_organization_project.json | 52 + ...der_organization_project_pipeline_run.json | 53 + ...rovider_organization_project_settings.json | 49 + ...jects_project_id_pipeline-definitions.json | 72 + ...ect_id_pipeline-definitions_pipeline_.json | 68 + .../projects_project_id_rollback.json | 48 + ...ojects_project_id_triggers_trigger_id.json | 31 + tests/CIRCLECI_API/schedule_schedule-id.json | 27 + .../test_context_context_id_delete.py | 90 + ...nvironment-variable_env_var_name_delete.py | 92 + ...d_environment-variable_env_var_name_put.py | 84 + ...ext_context_id_environment-variable_get.py | 148 + .../test_context_context_id_get.py | 84 + ...est_context_context_id_restrictions_get.py | 99 + ...st_context_context_id_restrictions_post.py | 141 + ...t_id_restrictions_restriction_id_delete.py | 102 + tests/CIRCLECI_API/test_context_get.py | 105 + tests/CIRCLECI_API/test_context_post.py | 163 + ...test_deploy_components_component_id_get.py | 107 + ...oy_components_component_id_versions_get.py | 96 + .../test_deploy_components_get.py | 102 + ..._deploy_environments_environment_id_get.py | 99 + .../test_deploy_environments_get.py | 122 + .../test_insights_org-slug_summary_get.py | 124 + ...insights_pages_project-slug_summary_get.py | 86 + ...test_insights_project-slug_branches_get.py | 105 + ...t_insights_project-slug_flaky-tests_get.py | 106 + ...est_insights_project-slug_workflows_get.py | 124 + ...roject-slug_workflows_workflow-name_get.py | 113 + ...t-slug_workflows_workflow-name_jobs_get.py | 119 + ...lug_workflows_workflow-name_summary_get.py | 100 + ...orkflows_workflow-name_test-metrics_get.py | 98 + ...t-slug_workflows_workflow-name_jobs_get.py | 103 + .../test_jobs_job-id_cancel_post.py | 103 + .../test_me_collaborations_get.py | 97 + tests/CIRCLECI_API/test_me_get.py | 99 + ...est_org_orgID_oidc-custom-claims_delete.py | 92 + .../test_org_orgID_oidc-custom-claims_get.py | 82 + ...test_org_orgID_oidc-custom-claims_patch.py | 123 + ...ect_projectID_oidc-custom-claims_delete.py | 72 + ...roject_projectID_oidc-custom-claims_get.py | 92 + ...ject_projectID_oidc-custom-claims_patch.py | 72 + ...test_organization_org-slug-or-id_delete.py | 107 + ...rganization_org-slug-or-id_project_post.py | 80 + ...b-allow-list_allow-list-entry-id_delete.py | 70 + ...n_org-slug-or-id_url-orb-allow-list_get.py | 98 + ..._org-slug-or-id_url-orb-allow-list_post.py | 94 + tests/CIRCLECI_API/test_organization_post.py | 111 + .../test_organizations_org_id_groups_get.py | 85 + ...nizations_org_id_groups_group_id_delete.py | 100 + ...rganizations_org_id_groups_group_id_get.py | 93 + .../test_organizations_org_id_groups_post.py | 108 + ...anizations_org_id_usage_export_job_post.py | 108 + ...sage_export_job_usage_export_job_id_get.py | 73 + ...context_context_decision_decisionID_get.py | 94 + ...t_decision_decisionID_policy-bundle_get.py | 120 + ...er_ownerID_context_context_decision_get.py | 90 + ...r_ownerID_context_context_decision_post.py | 90 + ...D_context_context_decision_settings_get.py | 112 + ...context_context_decision_settings_patch.py | 105 + ...nerID_context_context_policy-bundle_get.py | 109 + ...xt_context_policy-bundle_policyName_get.py | 124 + ...erID_context_context_policy-bundle_post.py | 87 + .../test_pipeline_continue_post.py | 105 + tests/CIRCLECI_API/test_pipeline_get.py | 84 + .../test_pipeline_pipeline-id_config_get.py | 79 + .../test_pipeline_pipeline-id_get.py | 102 + .../test_pipeline_pipeline-id_values_get.py | 101 + .../test_pipeline_pipeline-id_workflow_get.py | 61 + ...ct-slug_checkout-key_fingerprint_delete.py | 100 + ...oject-slug_checkout-key_fingerprint_get.py | 72 + ...t_project_project-slug_checkout-key_get.py | 67 + ..._project_project-slug_checkout-key_post.py | 102 + .../test_project_project-slug_delete.py | 96 + .../test_project_project-slug_envvar_get.py | 95 + ...project_project-slug_envvar_name_delete.py | 70 + ...st_project_project-slug_envvar_name_get.py | 81 + .../test_project_project-slug_envvar_post.py | 103 + .../test_project_project-slug_get.py | 89 + ...t_project-slug_job-number_artifacts_get.py | 70 + ...oject_project-slug_job-number_tests_get.py | 86 + ...project-slug_job_job-number_cancel_post.py | 109 + ...project_project-slug_job_job-number_get.py | 147 + .../test_project_project-slug_pipeline_get.py | 96 + ..._project_project-slug_pipeline_mine_get.py | 88 + ...oject-slug_pipeline_pipeline-number_get.py | 80 + ...test_project_project-slug_pipeline_post.py | 79 + .../test_project_project-slug_schedule_get.py | 93 + ...test_project_project-slug_schedule_post.py | 100 + ..._organization_project_pipeline_run_post.py | 119 + ...ject_provider_organization_project_post.py | 101 + ...vider_organization_project_settings_get.py | 101 + ...der_organization_project_settings_patch.py | 89 + ...cts_project_id_pipeline-definitions_get.py | 105 + ...finitions_pipeline_definition_id_delete.py | 78 + ...-definitions_pipeline_definition_id_get.py | 87 + ...efinitions_pipeline_definition_id_patch.py | 120 + ...ons_pipeline_definition_id_triggers_get.py | 85 + ...ns_pipeline_definition_id_triggers_post.py | 96 + ...ts_project_id_pipeline-definitions_post.py | 95 + .../test_projects_project_id_rollback_post.py | 104 + ...s_project_id_triggers_trigger_id_delete.py | 97 + ...ects_project_id_triggers_trigger_id_get.py | 68 + ...ts_project_id_triggers_trigger_id_patch.py | 65 + .../test_schedule_schedule-id_delete.py | 60 + .../test_schedule_schedule-id_get.py | 81 + .../test_schedule_schedule-id_patch.py | 106 + tests/CIRCLECI_API/test_user_id_get.py | 88 + tests/CIRCLECI_API/test_webhook_get.py | 93 + tests/CIRCLECI_API/test_webhook_post.py | 130 + .../test_webhook_webhook-id_delete.py | 92 + .../test_webhook_webhook-id_get.py | 72 + .../test_webhook_webhook-id_put.py | 111 + ...low_id_approve_approval_request_id_post.py | 83 + .../test_workflow_id_cancel_post.py | 97 + tests/CIRCLECI_API/test_workflow_id_get.py | 83 + .../CIRCLECI_API/test_workflow_id_job_get.py | 91 + .../test_workflow_id_rerun_post.py | 104 + tests/CIRCLECI_API/user_id.json | 26 + tests/CIRCLECI_API/validator.py | 225 + tests/CIRCLECI_API/webhook.json | 31 + tests/CIRCLECI_API/webhook_webhook-id.json | 27 + tests/CIRCLECI_API/workflow_id.json | 27 + ...rkflow_id_approve_approval_request_id.json | 32 + tests/CIRCLECI_API/workflow_id_cancel.json | 27 + tests/CIRCLECI_API/workflow_id_job.json | 26 + tests/CIRCLECI_API/workflow_id_rerun.json | 54 + 192 files changed, 37548 insertions(+) create mode 100644 Roost-README.md create mode 100644 requirements-roost.txt create mode 100644 tests/CIRCLECI_API/api.json create mode 100644 tests/CIRCLECI_API/config.yml create mode 100644 tests/CIRCLECI_API/conftest.py create mode 100644 tests/CIRCLECI_API/context.json create mode 100644 tests/CIRCLECI_API/context_context_id.json create mode 100644 tests/CIRCLECI_API/context_context_id_environment-variable.json create mode 100644 tests/CIRCLECI_API/context_context_id_environment-variable_env_var_na.json create mode 100644 tests/CIRCLECI_API/context_context_id_restrictions.json create mode 100644 tests/CIRCLECI_API/context_context_id_restrictions_restriction_id.json create mode 100644 tests/CIRCLECI_API/deploy_components.json create mode 100644 tests/CIRCLECI_API/deploy_components_component_id.json create mode 100644 tests/CIRCLECI_API/deploy_components_component_id_versions.json create mode 100644 tests/CIRCLECI_API/deploy_environments.json create mode 100644 tests/CIRCLECI_API/deploy_environments_environment_id.json create mode 100644 tests/CIRCLECI_API/insights_org-slug_summary.json create mode 100644 tests/CIRCLECI_API/insights_pages_project-slug_summary.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_branches.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_flaky-tests.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_workflows.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_jobs.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_summ.json create mode 100644 tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_test.json create mode 100644 tests/CIRCLECI_API/insights_time-series_project-slug_workflows_workfl.json create mode 100644 tests/CIRCLECI_API/jobs_job-id_cancel.json create mode 100644 tests/CIRCLECI_API/me.json create mode 100644 tests/CIRCLECI_API/me_collaborations.json create mode 100644 tests/CIRCLECI_API/org_orgID_oidc-custom-claims.json create mode 100644 tests/CIRCLECI_API/org_orgID_project_projectID_oidc-custom-claims.json create mode 100644 tests/CIRCLECI_API/organization.json create mode 100644 tests/CIRCLECI_API/organization_org-slug-or-id.json create mode 100644 tests/CIRCLECI_API/organization_org-slug-or-id_project.json create mode 100644 tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list.json create mode 100644 tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list_all.json create mode 100644 tests/CIRCLECI_API/organizations_org_id_groups.json create mode 100644 tests/CIRCLECI_API/organizations_org_id_groups_group_id.json create mode 100644 tests/CIRCLECI_API/organizations_org_id_usage_export_job.json create mode 100644 tests/CIRCLECI_API/organizations_org_id_usage_export_job_usage_export.json create mode 100644 tests/CIRCLECI_API/owner_ownerID_context_context_decision.json create mode 100644 tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID.json create mode 100644 tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID_.json create mode 100644 tests/CIRCLECI_API/owner_ownerID_context_context_decision_settings.json create mode 100644 tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle.json create mode 100644 tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle_policy.json create mode 100644 tests/CIRCLECI_API/pipeline.json create mode 100644 tests/CIRCLECI_API/pipeline_continue.json create mode 100644 tests/CIRCLECI_API/pipeline_pipeline-id.json create mode 100644 tests/CIRCLECI_API/pipeline_pipeline-id_config.json create mode 100644 tests/CIRCLECI_API/pipeline_pipeline-id_values.json create mode 100644 tests/CIRCLECI_API/pipeline_pipeline-id_workflow.json create mode 100644 tests/CIRCLECI_API/project_project-slug.json create mode 100644 tests/CIRCLECI_API/project_project-slug_checkout-key.json create mode 100644 tests/CIRCLECI_API/project_project-slug_checkout-key_fingerprint.json create mode 100644 tests/CIRCLECI_API/project_project-slug_envvar.json create mode 100644 tests/CIRCLECI_API/project_project-slug_envvar_name.json create mode 100644 tests/CIRCLECI_API/project_project-slug_job-number_artifacts.json create mode 100644 tests/CIRCLECI_API/project_project-slug_job-number_tests.json create mode 100644 tests/CIRCLECI_API/project_project-slug_job_job-number.json create mode 100644 tests/CIRCLECI_API/project_project-slug_job_job-number_cancel.json create mode 100644 tests/CIRCLECI_API/project_project-slug_pipeline.json create mode 100644 tests/CIRCLECI_API/project_project-slug_pipeline_mine.json create mode 100644 tests/CIRCLECI_API/project_project-slug_pipeline_pipeline-number.json create mode 100644 tests/CIRCLECI_API/project_project-slug_schedule.json create mode 100644 tests/CIRCLECI_API/project_provider_organization_project.json create mode 100644 tests/CIRCLECI_API/project_provider_organization_project_pipeline_run.json create mode 100644 tests/CIRCLECI_API/project_provider_organization_project_settings.json create mode 100644 tests/CIRCLECI_API/projects_project_id_pipeline-definitions.json create mode 100644 tests/CIRCLECI_API/projects_project_id_pipeline-definitions_pipeline_.json create mode 100644 tests/CIRCLECI_API/projects_project_id_rollback.json create mode 100644 tests/CIRCLECI_API/projects_project_id_triggers_trigger_id.json create mode 100644 tests/CIRCLECI_API/schedule_schedule-id.json create mode 100644 tests/CIRCLECI_API/test_context_context_id_delete.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_delete.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_put.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_environment-variable_get.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_get.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_restrictions_get.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_restrictions_post.py create mode 100644 tests/CIRCLECI_API/test_context_context_id_restrictions_restriction_id_delete.py create mode 100644 tests/CIRCLECI_API/test_context_get.py create mode 100644 tests/CIRCLECI_API/test_context_post.py create mode 100644 tests/CIRCLECI_API/test_deploy_components_component_id_get.py create mode 100644 tests/CIRCLECI_API/test_deploy_components_component_id_versions_get.py create mode 100644 tests/CIRCLECI_API/test_deploy_components_get.py create mode 100644 tests/CIRCLECI_API/test_deploy_environments_environment_id_get.py create mode 100644 tests/CIRCLECI_API/test_deploy_environments_get.py create mode 100644 tests/CIRCLECI_API/test_insights_org-slug_summary_get.py create mode 100644 tests/CIRCLECI_API/test_insights_pages_project-slug_summary_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_branches_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_flaky-tests_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_workflows_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_jobs_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_summary_get.py create mode 100644 tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_test-metrics_get.py create mode 100644 tests/CIRCLECI_API/test_insights_time-series_project-slug_workflows_workflow-name_jobs_get.py create mode 100644 tests/CIRCLECI_API/test_jobs_job-id_cancel_post.py create mode 100644 tests/CIRCLECI_API/test_me_collaborations_get.py create mode 100644 tests/CIRCLECI_API/test_me_get.py create mode 100644 tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_delete.py create mode 100644 tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_get.py create mode 100644 tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_patch.py create mode 100644 tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_delete.py create mode 100644 tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_get.py create mode 100644 tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_patch.py create mode 100644 tests/CIRCLECI_API/test_organization_org-slug-or-id_delete.py create mode 100644 tests/CIRCLECI_API/test_organization_org-slug-or-id_project_post.py create mode 100644 tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_allow-list-entry-id_delete.py create mode 100644 tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_get.py create mode 100644 tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_post.py create mode 100644 tests/CIRCLECI_API/test_organization_post.py create mode 100644 tests/CIRCLECI_API/test_organizations_org_id_groups_get.py create mode 100644 tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_delete.py create mode 100644 tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_get.py create mode 100644 tests/CIRCLECI_API/test_organizations_org_id_groups_post.py create mode 100644 tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_post.py create mode 100644 tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_usage_export_job_id_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_policy-bundle_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_post.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_patch.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_policyName_get.py create mode 100644 tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_post.py create mode 100644 tests/CIRCLECI_API/test_pipeline_continue_post.py create mode 100644 tests/CIRCLECI_API/test_pipeline_get.py create mode 100644 tests/CIRCLECI_API/test_pipeline_pipeline-id_config_get.py create mode 100644 tests/CIRCLECI_API/test_pipeline_pipeline-id_get.py create mode 100644 tests/CIRCLECI_API/test_pipeline_pipeline-id_values_get.py create mode 100644 tests/CIRCLECI_API/test_pipeline_pipeline-id_workflow_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_delete.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_checkout-key_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_checkout-key_post.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_delete.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_envvar_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_envvar_name_delete.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_envvar_name_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_envvar_post.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_job-number_artifacts_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_job-number_tests_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_job_job-number_cancel_post.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_job_job-number_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_pipeline_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_pipeline_mine_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_pipeline_pipeline-number_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_pipeline_post.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_schedule_get.py create mode 100644 tests/CIRCLECI_API/test_project_project-slug_schedule_post.py create mode 100644 tests/CIRCLECI_API/test_project_provider_organization_project_pipeline_run_post.py create mode 100644 tests/CIRCLECI_API/test_project_provider_organization_project_post.py create mode 100644 tests/CIRCLECI_API/test_project_provider_organization_project_settings_get.py create mode 100644 tests/CIRCLECI_API/test_project_provider_organization_project_settings_patch.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_get.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_delete.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_get.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_patch.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_get.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_post.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_post.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_rollback_post.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_delete.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_get.py create mode 100644 tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_patch.py create mode 100644 tests/CIRCLECI_API/test_schedule_schedule-id_delete.py create mode 100644 tests/CIRCLECI_API/test_schedule_schedule-id_get.py create mode 100644 tests/CIRCLECI_API/test_schedule_schedule-id_patch.py create mode 100644 tests/CIRCLECI_API/test_user_id_get.py create mode 100644 tests/CIRCLECI_API/test_webhook_get.py create mode 100644 tests/CIRCLECI_API/test_webhook_post.py create mode 100644 tests/CIRCLECI_API/test_webhook_webhook-id_delete.py create mode 100644 tests/CIRCLECI_API/test_webhook_webhook-id_get.py create mode 100644 tests/CIRCLECI_API/test_webhook_webhook-id_put.py create mode 100644 tests/CIRCLECI_API/test_workflow_id_approve_approval_request_id_post.py create mode 100644 tests/CIRCLECI_API/test_workflow_id_cancel_post.py create mode 100644 tests/CIRCLECI_API/test_workflow_id_get.py create mode 100644 tests/CIRCLECI_API/test_workflow_id_job_get.py create mode 100644 tests/CIRCLECI_API/test_workflow_id_rerun_post.py create mode 100644 tests/CIRCLECI_API/user_id.json create mode 100644 tests/CIRCLECI_API/validator.py create mode 100644 tests/CIRCLECI_API/webhook.json create mode 100644 tests/CIRCLECI_API/webhook_webhook-id.json create mode 100644 tests/CIRCLECI_API/workflow_id.json create mode 100644 tests/CIRCLECI_API/workflow_id_approve_approval_request_id.json create mode 100644 tests/CIRCLECI_API/workflow_id_cancel.json create mode 100644 tests/CIRCLECI_API/workflow_id_job.json create mode 100644 tests/CIRCLECI_API/workflow_id_rerun.json diff --git a/Roost-README.md b/Roost-README.md new file mode 100644 index 00000000..dd5bcc8d --- /dev/null +++ b/Roost-README.md @@ -0,0 +1,25 @@ + +# RoostGPT generated pytest code for API Testing + +RoostGPT generats code in `tests` folder within given project path. +Dependency file i.e. `requirements-roost.txt` is also created in the given project path + +Below are the sample steps to run the generated tests. Sample commands contains use of package manager i.e. `uv`. Alternatively python and pip can be used directly. +1. ( Optional ) Create virtual Env . +2. Install dependencies +``` +uv venv // Create virtual Env +uv pip install -r requirements-roost.txt // Install all dependencies + +``` + +Test configurations and test_data is loaded from config.yml. e.g. API HOST, auth, common path parameters of endpoint. +Either set defalt value in this config.yml file OR use ENV. e.g. export API_HOST="https://example.com/api/v2" + +Once configuration values are set, use below commands to run the tests. +``` +// Run generated tests +uv run pytest -m smoke // Run only smoke tests +uv run pytest -s tests/generated-test.py // Run specific test file +``` + \ No newline at end of file diff --git a/requirements-roost.txt b/requirements-roost.txt new file mode 100644 index 00000000..7f3f1f60 --- /dev/null +++ b/requirements-roost.txt @@ -0,0 +1,2 @@ + +pytest \ No newline at end of file diff --git a/tests/CIRCLECI_API/api.json b/tests/CIRCLECI_API/api.json new file mode 100644 index 00000000..9fd67119 --- /dev/null +++ b/tests/CIRCLECI_API/api.json @@ -0,0 +1,23564 @@ +{ + "openapi": "3.0.3", + "info": { + "version": "v2", + "title": "CircleCI API", + "description": "This describes the resources that make up the CircleCI API v2.", + "license": { + "name": "MIT", + "url": "https://opensource.org/license/MIT" + } + }, + "servers": [ + { + "url": "https://circleci.com/api/v2" + } + ], + "security": [ + { + "api_key_header": [] + }, + { + "basic_auth": [] + }, + { + "api_key_query": [] + } + ], + "tags": [ + { + "name": "Context", + "description": "Endpoints relating to [contexts](https://circleci.com/docs/contexts/). Use contexts to secure and share environment variables." + }, + { + "name": "Insights", + "description": "Endpoints relating to [Insights](https://circleci.com/docs/insights/). Use Insights to monitor credit and compute usage for your projects." + }, + { + "name": "User", + "description": "A set of endpoints you can use to get information about a specific user." + }, + { + "name": "Pipeline", + "description": "Endpoints relating to [pipelines](https://circleci.com/docs/pipelines/). Get information about your pipelines. Trigger or continue a pipeline." + }, + { + "name": "Job", + "description": "Endpoints relating to [jobs](https://circleci.com/docs/jobs-steps/). Get information about your jobs, retrieve job assets, cancel a job." + }, + { + "name": "Workflow", + "description": "Endpoints relating to [workflows](https://circleci.com/docs/workflows/). Get information about your workflows, or interact with them to rerun, cancel or approve a job." + }, + { + "name": "Webhook", + "description": "Endpoints relating to [outbound webhooks](https://circleci.com/docs/outbound-webhooks/). Use outbound webhooks to integrate your CircleCI builds with external services." + }, + { + "description": "Endpoints related to manage oidc identity tokens", + "name": "OIDC Token Management" + }, + { + "description": "Endpoints related to managing policies and making policy decisions", + "name": "Policy Management" + }, + { + "name": "Deploy", + "description": "Endpoints related to deploy management." + }, + { + "name": "Pipeline Definition", + "description": "Endpoints related to creating and managing pipeline definitions." + }, + { + "name": "Project", + "description": "Endpoints related to creating and managing a project." + }, + { + "name": "Rollback", + "description": "Endpoints related to creating and managing a rollback." + }, + { + "name": "Trigger", + "description": "Endpoints related to creating and managing triggers." + }, + { + "name": "Usage", + "description": "Endpoints related to organization usage exports.\n\nThe Usage API is an API provided by CircleCI to customers to access all of their usage data on CircleCI. It contains all the metadata (org, project, pipeline, workflow, and job dimensions) as well as credit consumption data. It is provided at the near lowest level of granularity (at the job run level).\n\n__Restrictions__\n\n* Max result set size of 100MB\n* Query timeout of 4 hours.\n* Max date window of 32 days\n* 13 months of historical data is available\n* No PII is surfaced in the Usage API (e.g. email address, Github login name)\n* The POST endpoint can only be queried up to (i.e. is rate limited to) 10 times per hour per org\n* The GET endpoint can only be queried up to (i.e. is rate limited to) 10 times per hour per org\n* To increase performance the API can generate multiple CSV files that need to be merged after download\n\n__Requirements__\n\n* organization ID - To get your organization ID go to to Organization Settings tab in the CircleCI app. ie https://app.circleci.com/settings/organization///overview\n* API Personal Access Token - https://circleci.com/docs/managing-api-tokens/\n\n__Report Fields__\n\n| | Field | Description |\n|---------------------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| | organization_id | The org ID |\n| | organization_name | The org name |\n| | organization_created_date | The date (UTC) that the org was created |\n| Project-level attributes | project_id | The project ID / token |\n| | project_name | The project name. For classic orgs, the project name is inherited from Github. For standalone, the org is set by the user. |\n| | project_created_date | The date (UTC) that the project was created. For classic orgs, this is the date that the repo was authorized on CircleCI. For standalone orgs, this is the date that the project was created on CircleCI |\n| | last_build_finished_at | The date (UTC) of the last pipeline run on this project |\n| Pipeline-level attributes | vcs_name | The name of the VCS connected to the project on which the pipeline was run |\n| | vcs_url | The URL of the VCS on which the pipeline was run |\n| | vcs_branch | The branch on which the pipeline was run |\n| | pipeline_id | The ID of the pipeline instance that was triggered. If a pipeline is re-run, it will share the same pipeline ID as the original pipeline instance |\n| | pipeline_created_at | The date (UTC) the pipeline instance was first triggered |\n| | pipeline_number | The pipeline number |\n| | is_unregistered_user | Y/N flag of whether the pipeline was triggered by a CircleCI user or a user not registered on CircleCI. Examples of the latter include users who commit on a connected VCS and consume credits on CircleCI. |\n| | pipeline_trigger_source | The source of the pipeline instance trigger (API, webhook, etc.) |\n| | pipeline_trigger_user_id | The user ID / token of the user who triggered the pipeline |\n| Workflow-level attributes | workflow_id | The ID of the workflow instance that was triggered |\n| | workflow_name | The name of the workflow |\n| | workflow_first_job_queued_at | The timestamp (UTC) of when the workflow instance started to queue |\n| | workflow_first_job_started_at | The timestamp (UTC) of when the workflow instance started to run |\n| | workflow_stopped_at | The timestamp (UTC) of when the workflow instance stopped |\n| | is_workflow_successful | Y/N flag of whether all jobs in the workflow were successfully ran |\n| Job-level attributes | job_name | The name of the job (the name the customer sees in the UI) |\n| | job_id | The ID of the job run instance that was triggered |\n| | job_run_number | The number of the job run instance that was triggered |\n| | job_run_date | The date (UTC) of the job run instance began |\n| | job_run_queued_at | The timestamp (UTC) of when the job started to queue |\n| | job_run_started_at | The timestamp (UTC) of when the job started to run |\n| | job_run_stopped_at | The timestamp (UTC) of when the job stopped |\n| | job_build_status | The status of the job run instance |\n| | resource_class | The resource class of the job run instance |\n| | operating_system | The operating system of the job run instance |\n| | executor | The executor of the job run instance |\n| | parallelism | The parallelism of the job run instance |\n| | job_run_seconds | The duration in seconds of the job run instance |\n| | median_cpu_utilization_pct | The median CPU utilization calculated over the course of the entire job run instance. CPU utilization is logged every 15 seconds. It will not be available for any jobs under 15 seconds and occasionally will not be available for jobs greater than 15 seconds. |\n| | max_cpu_utilization_pct | The max CPU utilization logged over the course of the entire job run instance. CPU utilization is logged every 15 seconds. It will not be available for any jobs under 15 seconds and occasionally will not be available for jobs greater than 15 seconds. |\n| | median_ram_utilization_pct | The median RAM utilization calculated over the course of the entire job run instance. RAM utilization is logged every 15 seconds. It will not be available for any jobs under 15 seconds and occasionally will not be available for jobs greater than 15 seconds. |\n| | max_ram_utilization_pct | The max RAM utilization logged over the course of the entire job run instance. RAM utilization is logged every 15 seconds. It will not be available for any jobs under 15 seconds and occasionally will not be available for jobs greater than 15 seconds. |\n| Credit consumption metrics | compute_credits | The compute credits consumed by this job run instance |\n| | dlc_credits | The docker-layer caching credits consumed by this job run instance |\n| | user_credits | The user credits consumed by this job run instance |\n| | storage_credits | The storage credits consumed by this job run instance. Note: When an organization is below its allocated storage threshold, a job that uses storage will have 0 storage credits applied. The organization's included storage threshold can be found on the [CircleCI web app](https://app.circleci.com/home) by navigating to **Plan > Plan Usage**. |\n| | network_credits | The network credits consumed by this job run instance |\n| | lease_credits | The lease credits consumed by this job run instance |\n| | lease_overage_credits | The lease overage credits consumed by this job run instance |\n| | ipranges_credits | The IP ranges credits consumed by this job run instance |\n| | total_credits | The total credits consumed by this job run instance |\n" + } + ], + "paths": { + "/insights/pages/{project-slug}/summary": { + "get": { + "summary": "Get summary metrics and trends for a project across it's workflows and branches", + "description": "Get summary metrics and trends for a project at workflow and branch level.\n Workflow runs going back at most 90 days are included in the aggregation window.\n Trends are only supported upto last 30 days.\n Please note that Insights is not a financial reporting tool and should not be used for precise credit reporting. Credit reporting from Insights does not use the same source of truth as the billing information that is found in the Plan Overview page in the CircleCI UI, nor does the underlying data have the same data accuracy guarantees as the billing information in the CircleCI UI. This may lead to discrepancies between credits reported from Insights and the billing information in the Plan Overview page of the CircleCI UI. For precise credit reporting, always use the Plan Overview page in the CircleCI UI.", + "tags": [ + "Insights" + ], + "operationId": "getProjectWorkflowsPageData", + "responses": { + "200": { + "description": "Aggregated summary metrics and trends by workflow and branches", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "org_id": { + "description": "The unique ID of the organization" + }, + "project_id": { + "description": "The unique ID of the project" + }, + "project_data": { + "type": "object", + "properties": { + "metrics": { + "type": "object", + "properties": { + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "total_duration_secs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "Total duration, in seconds." + }, + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed over the current timeseries interval." + }, + "success_rate": { + "type": "number", + "format": "float" + }, + "throughput": { + "type": "number", + "format": "float", + "description": "The average number of runs per day." + } + }, + "required": [ + "total_runs", + "total_duration_secs", + "total_credits_used", + "success_rate", + "throughput" + ], + "description": "Metrics aggregated across all workflows and branches for a project." + }, + "trends": { + "type": "object", + "properties": { + "total_runs": { + "type": "number", + "format": "float", + "description": "The trend value for total number of runs." + }, + "total_duration_secs": { + "type": "number", + "format": "float", + "description": "Trend value for total duration." + }, + "total_credits_used": { + "type": "number", + "format": "float", + "description": "The trend value for total credits consumed." + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The trend value for the success rate." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "Trend value for the average number of runs per day." + } + }, + "required": [ + "total_runs", + "total_duration_secs", + "total_credits_used", + "success_rate", + "throughput" + ], + "description": "Metric trends aggregated across all workflows and branches for a project." + } + }, + "required": [ + "metrics", + "trends" + ], + "description": "Metrics and trends data aggregated for a given project." + }, + "project_workflow_data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "workflow_name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "metrics": { + "type": "object", + "properties": { + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed over the current timeseries interval." + }, + "p95_duration_secs": { + "type": "number", + "format": "float", + "description": "The 95th percentile duration among a group of workflow runs." + }, + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "success_rate": { + "type": "number", + "format": "float" + } + }, + "required": [ + "total_credits_used", + "p95_duration_secs", + "total_runs", + "success_rate" + ], + "description": "Metrics aggregated across a workflow or branchfor a project." + }, + "trends": { + "type": "object", + "properties": { + "total_credits_used": { + "type": "number", + "format": "float", + "description": "The trend value for total credits consumed." + }, + "p95_duration_secs": { + "type": "number", + "format": "float", + "description": "The 95th percentile duration among a group of workflow runs." + }, + "total_runs": { + "type": "number", + "format": "float", + "description": "The trend value for total number of runs." + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The trend value for the success rate." + } + }, + "required": [ + "total_credits_used", + "p95_duration_secs", + "total_runs", + "success_rate" + ], + "description": "Trends aggregated across a workflow or branch for a project." + } + }, + "required": [ + "workflow_name", + "metrics", + "trends" + ] + }, + "description": "A list of metrics and trends data for workflows for a given project." + }, + "project_workflow_branch_data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "workflow_name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "branch": { + "type": "string", + "description": "The VCS branch of a workflow's trigger.", + "example": "main" + }, + "metrics": { + "type": "object", + "properties": { + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed over the current timeseries interval." + }, + "p95_duration_secs": { + "type": "number", + "format": "float", + "description": "The 95th percentile duration among a group of workflow runs." + }, + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "success_rate": { + "type": "number", + "format": "float" + } + }, + "required": [ + "total_credits_used", + "p95_duration_secs", + "total_runs", + "success_rate" + ], + "description": "Metrics aggregated across a workflow or branchfor a project." + }, + "trends": { + "type": "object", + "properties": { + "total_credits_used": { + "type": "number", + "format": "float", + "description": "The trend value for total credits consumed." + }, + "p95_duration_secs": { + "type": "number", + "format": "float", + "description": "The 95th percentile duration among a group of workflow runs." + }, + "total_runs": { + "type": "number", + "format": "float", + "description": "The trend value for total number of runs." + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The trend value for the success rate." + } + }, + "required": [ + "total_credits_used", + "p95_duration_secs", + "total_runs", + "success_rate" + ], + "description": "Trends aggregated across a workflow or branch for a project." + } + }, + "required": [ + "workflow_name", + "branch", + "metrics", + "trends" + ] + }, + "description": "A list of metrics and trends data for branches for a given project." + }, + "all_branches": { + "type": "array", + "items": { + "type": "string", + "description": "The VCS branch of a workflow's trigger.", + "example": "main" + }, + "description": "A list of all the branches for a given project." + }, + "all_workflows": { + "type": "array", + "items": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "description": "A list of all the workflows for a given project." + } + } + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "reporting-window", + "description": "The time window used to calculate summary metrics. If not provided, defaults to last-90-days", + "schema": { + "type": "string" + }, + "required": false, + "example": "last-90-days" + }, + { + "in": "query", + "name": "branches", + "description": "The names of VCS branches to include in branch-level workflow metrics.", + "schema": { + "type": "object" + }, + "required": false, + "example": "A single branch: ?branches=main or for multiple branches: ?branches=main&branches=feature&branches=dev" + }, + { + "in": "query", + "name": "workflow-names", + "description": "The names of workflows to include in workflow-level metrics.", + "schema": { + "type": "object" + }, + "required": false, + "example": "A single workflow name: ?workflow-names=build-test-deploy or\n for multiple workflow names: ?workflow-names=build&workflow-names=test-and-deploy." + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/pages/gh/CircleCI-Public/api-preview-docs/summary?reporting-window=last-90-days&branches=A%20single%20branch%3A%20%3Fbranches%3Dmain%20or%20for%20multiple%20branches%3A%20%3Fbranches%3Dmain%26branches%3Dfeature%26branches%3Ddev&workflow-names=A%20single%20workflow%20name%3A%20%3Fworkflow-names%3Dbuild-test-deploy%20or%0A%20%20%20%20for%20multiple%20workflow%20names%3A%20%3Fworkflow-names%3Dbuild%26workflow-names%3Dtest-and-deploy.\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/pages/gh/CircleCI-Public/api-preview-docs/summary?reporting-window=last-90-days&branches=A%20single%20branch%3A%20%3Fbranches%3Dmain%20or%20for%20multiple%20branches%3A%20%3Fbranches%3Dmain%26branches%3Dfeature%26branches%3Ddev&workflow-names=A%20single%20workflow%20name%3A%20%3Fworkflow-names%3Dbuild-test-deploy%20or%0A%20%20%20%20for%20multiple%20workflow%20names%3A%20%3Fworkflow-names%3Dbuild%26workflow-names%3Dtest-and-deploy.';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/pages/gh/CircleCI-Public/api-preview-docs/summary?reporting-window=last-90-days&branches=A%20single%20branch%3A%20%3Fbranches%3Dmain%20or%20for%20multiple%20branches%3A%20%3Fbranches%3Dmain%26branches%3Dfeature%26branches%3Ddev&workflow-names=A%20single%20workflow%20name%3A%20%3Fworkflow-names%3Dbuild-test-deploy%20or%0A%20%20%20%20for%20multiple%20workflow%20names%3A%20%3Fworkflow-names%3Dbuild%26workflow-names%3Dtest-and-deploy.\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/pages/gh/CircleCI-Public/api-preview-docs/summary?reporting-window=last-90-days&branches=A%20single%20branch%3A%20%3Fbranches%3Dmain%20or%20for%20multiple%20branches%3A%20%3Fbranches%3Dmain%26branches%3Dfeature%26branches%3Ddev&workflow-names=A%20single%20workflow%20name%3A%20%3Fworkflow-names%3Dbuild-test-deploy%20or%0A%20%20%20%20for%20multiple%20workflow%20names%3A%20%3Fworkflow-names%3Dbuild%26workflow-names%3Dtest-and-deploy.\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/pages/gh/CircleCI-Public/api-preview-docs/summary?reporting-window=last-90-days&branches=A%20single%20branch%3A%20%3Fbranches%3Dmain%20or%20for%20multiple%20branches%3A%20%3Fbranches%3Dmain%26branches%3Dfeature%26branches%3Ddev&workflow-names=A%20single%20workflow%20name%3A%20%3Fworkflow-names%3Dbuild-test-deploy%20or%0A%20%20%20%20for%20multiple%20workflow%20names%3A%20%3Fworkflow-names%3Dbuild%26workflow-names%3Dtest-and-deploy.\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/time-series/{project-slug}/workflows/{workflow-name}/jobs": { + "get": { + "summary": "Job timeseries data", + "description": "Get timeseries data for all jobs within a workflow. Hourly granularity data is only retained for 48 hours while daily granularity data is retained for 90 days.", + "tags": [ + "Insights" + ], + "operationId": "getJobTimeseries", + "responses": { + "200": { + "description": "An array of timeseries data, one entry per job.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "min_started_at": { + "type": "string", + "format": "date-time", + "description": "The start time for the earliest execution included in the metrics." + }, + "max_ended_at": { + "type": "string", + "format": "date-time", + "description": "The end time of the last execution included in the metrics." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "The start of the interval for timeseries metrics." + }, + "metrics": { + "type": "object", + "properties": { + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "failed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of failed runs." + }, + "successful_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of successful runs." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "The average number of runs per day." + }, + "median_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The median credits consumed over the current timeseries interval." + }, + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed over the current timeseries interval." + }, + "duration_metrics": { + "type": "object", + "properties": { + "min": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The minimum duration, in seconds, among a group of runs." + }, + "median": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The median duration, in seconds, among a group of runs." + }, + "max": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The max duration, in seconds, among a group of runs." + }, + "p95": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The 95th percentile duration, in seconds, among a group of runs." + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The total duration, in seconds, added across a group of runs." + } + }, + "required": [ + "min", + "median", + "max", + "p95", + "total" + ], + "description": "Metrics relating to the duration of runs for a workflow." + } + }, + "required": [ + "total_runs", + "failed_runs", + "successful_runs", + "throughput", + "median_credits_used", + "total_credits_used", + "duration_metrics" + ], + "description": "Metrics relating to a workflow's runs." + } + }, + "required": [ + "name", + "min_started_at", + "max_ended_at", + "timestamp", + "metrics" + ] + }, + "description": "Aggregate metrics for a workflow at a time granularity" + } + }, + "required": [ + "next_page_token", + "items" + ], + "description": "Project level timeseries metrics response" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "workflow-name", + "description": "The name of the workflow.", + "schema": { + "type": "string" + }, + "required": true, + "example": "build-and-test" + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch. If not passed we will scope the API call to the default branch.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "in": "query", + "name": "granularity", + "description": "The granularity for which to query timeseries data.", + "schema": { + "type": "string" + }, + "required": false, + "example": "hourly" + }, + { + "in": "query", + "name": "start-date", + "description": "Include only executions that started at or after this date. This must be specified if an end-date is provided.", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-08-21T13:26:29Z" + }, + { + "in": "query", + "name": "end-date", + "description": "Include only executions that started before this date. This date can be at most 90 days after the start-date.", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-09-04T13:26:29Z" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/time-series/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?branch=example-value&granularity=hourly&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/time-series/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?branch=example-value&granularity=hourly&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/time-series/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?branch=example-value&granularity=hourly&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/time-series/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?branch=example-value&granularity=hourly&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/time-series/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?branch=example-value&granularity=hourly&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{org-slug}/summary": { + "get": { + "summary": "Get summary metrics with trends for the entire org, and for each project.", + "description": "Gets aggregated summary metrics with trends for the entire org.\n Also gets aggregated metrics and trends for each project belonging to the org.", + "tags": [ + "Insights" + ], + "operationId": "getOrgSummaryData", + "responses": { + "200": { + "description": "summary metrics with trends for an entire org and it's projects.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "org_data": { + "type": "object", + "properties": { + "metrics": { + "type": "object", + "properties": { + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "total_duration_secs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "Total duration, in seconds." + }, + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed over the current timeseries interval." + }, + "success_rate": { + "type": "number", + "format": "float" + }, + "throughput": { + "type": "number", + "format": "float", + "description": "The average number of runs per day." + } + }, + "required": [ + "total_runs", + "total_duration_secs", + "total_credits_used", + "success_rate", + "throughput" + ], + "description": "Metrics for a single org metrics." + }, + "trends": { + "type": "object", + "properties": { + "total_runs": { + "type": "number", + "format": "float", + "description": "The trend value for total number of runs." + }, + "total_duration_secs": { + "type": "number", + "format": "float", + "description": "Trend value for total duration." + }, + "total_credits_used": { + "type": "number", + "format": "float", + "description": "The trend value for total credits consumed." + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The trend value for the success rate." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "Trend value for the average number of runs per day." + } + }, + "required": [ + "total_runs", + "total_duration_secs", + "total_credits_used", + "success_rate", + "throughput" + ], + "description": "Trends for a single org." + } + }, + "required": [ + "metrics", + "trends" + ], + "description": "Aggregated metrics for an org, with trends." + }, + "org_project_data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "project_name": { + "type": "string", + "description": "The name of the project.", + "example": "api-preview-docs" + }, + "metrics": { + "type": "object", + "properties": { + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed over the current timeseries interval." + }, + "total_duration_secs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "Total duration, in seconds." + }, + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "success_rate": { + "type": "number", + "format": "float" + } + }, + "required": [ + "total_credits_used", + "total_duration_secs", + "total_runs", + "success_rate" + ], + "description": "Metrics for a single project, across all branches." + }, + "trends": { + "type": "object", + "properties": { + "total_credits_used": { + "type": "number", + "format": "float", + "description": "The trend value for total credits consumed." + }, + "total_duration_secs": { + "type": "number", + "format": "float", + "description": "Trend value for total duration." + }, + "total_runs": { + "type": "number", + "format": "float", + "description": "The trend value for total number of runs." + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The trend value for the success rate." + } + }, + "required": [ + "total_credits_used", + "total_duration_secs", + "total_runs", + "success_rate" + ], + "description": "Trends for a single project, across all branches." + } + }, + "required": [ + "project_name", + "metrics", + "trends" + ] + }, + "description": "Metrics for a single project, across all branches" + }, + "all_projects": { + "type": "array", + "items": { + "type": "string" + }, + "x-nullable": true, + "description": "A list of all the project names in the organization." + } + }, + "required": [ + "org_data", + "org_project_data", + "all_projects" + ], + "description": "Summary metrics with trends for the entire org, and for each project." + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "org-slug", + "description": "Org slug in the form `vcs-slug/org-name`. The `/` characters may be URL-escaped.", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public" + }, + { + "in": "query", + "name": "reporting-window", + "description": "The time window used to calculate summary metrics. If not provided, defaults to last-90-days", + "schema": { + "type": "string" + }, + "required": false, + "example": "last-90-days" + }, + { + "in": "query", + "name": "project-names", + "description": "List of project names.", + "schema": { + "type": "object" + }, + "required": false, + "example": "For a single project: ?project-names=some-project or for multiple projects: ?project-names=some-project1&project-names=some-project2" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/summary?reporting-window=last-90-days&project-names=For%20a%20single%20project%3A%20%3Fproject-names%3Dsome-project%20or%20for%20multiple%20projects%3A%20%3Fproject-names%3Dsome-project1%26project-names%3Dsome-project2\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/summary?reporting-window=last-90-days&project-names=For%20a%20single%20project%3A%20%3Fproject-names%3Dsome-project%20or%20for%20multiple%20projects%3A%20%3Fproject-names%3Dsome-project1%26project-names%3Dsome-project2';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/summary?reporting-window=last-90-days&project-names=For%20a%20single%20project%3A%20%3Fproject-names%3Dsome-project%20or%20for%20multiple%20projects%3A%20%3Fproject-names%3Dsome-project1%26project-names%3Dsome-project2\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/summary?reporting-window=last-90-days&project-names=For%20a%20single%20project%3A%20%3Fproject-names%3Dsome-project%20or%20for%20multiple%20projects%3A%20%3Fproject-names%3Dsome-project1%26project-names%3Dsome-project2\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/summary?reporting-window=last-90-days&project-names=For%20a%20single%20project%3A%20%3Fproject-names%3Dsome-project%20or%20for%20multiple%20projects%3A%20%3Fproject-names%3Dsome-project1%26project-names%3Dsome-project2\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/branches": { + "get": { + "summary": "Get all branches for a project", + "description": "Get a list of all branches for a specified project. The list will only contain branches currently available within Insights. The maximum number of branches returned by this endpoint is 5,000.", + "tags": [ + "Insights" + ], + "operationId": "getAllInsightsBranches", + "responses": { + "200": { + "description": "A list of branches for a project", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "org_id": { + "description": "The unique ID of the organization" + }, + "project_id": { + "description": "The unique ID of the project" + }, + "branches": { + "type": "array", + "items": { + "type": "string", + "description": "The VCS branch of a workflow's trigger.", + "example": "main" + }, + "description": "A list of all the branches for a given project." + } + }, + "required": [ + "org_id", + "project_id", + "branches" + ], + "description": "Project branches response." + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "workflow-name", + "description": "The name of a workflow. If not passed we will scope the API call to the project.", + "schema": { + "type": "string" + }, + "required": false, + "example": "build-and-test" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/branches?workflow-name=build-and-test\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/branches?workflow-name=build-and-test';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/branches?workflow-name=build-and-test\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/branches?workflow-name=build-and-test\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/branches?workflow-name=build-and-test\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/flaky-tests": { + "get": { + "summary": "Get flaky tests for a project", + "description": "Get a list of flaky tests for a given project. Flaky tests are branch agnostic.\n A flaky test is a test that passed and failed in the same commit.", + "tags": [ + "Insights" + ], + "operationId": "getFlakyTests", + "responses": { + "200": { + "description": "A list of flaky tests for a project", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "flaky-tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "time-wasted": { + "allOf": [ + { + "type": "integer", + "format": "int64" + }, + { + "type": "integer", + "format": "int64", + "minimum": 0 + } + ] + }, + "workflow-created-at": { + "type": "string", + "description": "The date and time when workflow was created." + }, + "workflow-id": { + "description": "The ID of the workflow associated with the provided test counts" + }, + "classname": { + "type": "string", + "x-nullable": true, + "description": "The class the test belongs to." + }, + "pipeline-number": { + "allOf": [ + { + "type": "integer", + "format": "int64" + }, + { + "type": "integer", + "format": "int64", + "minimum": 0 + } + ], + "description": "The number of the pipeline." + }, + "workflow-name": { + "type": "string", + "description": "The name of the workflow." + }, + "test-name": { + "type": "string", + "description": "The name of the test." + }, + "job-name": { + "type": "string", + "description": "The name of the job." + }, + "job-number": { + "allOf": [ + { + "type": "integer", + "format": "int64" + }, + { + "type": "integer", + "format": "int64", + "minimum": 0 + } + ], + "description": "The number of the job." + }, + "times-flaked": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of times the test flaked." + }, + "source": { + "type": "string", + "x-nullable": true, + "description": "The source of the test." + }, + "file": { + "type": "string", + "x-nullable": true, + "description": "The file the test belongs to." + } + }, + "required": [ + "workflow-created-at", + "classname", + "job-number", + "times-flaked", + "source", + "pipeline-number", + "file", + "workflow-name", + "job-name", + "workflow-id", + "test-name" + ] + }, + "description": "A list of all instances of flakes. Note that a test is no longer considered flaky after 2 weeks have passed without a flake. Each flake resets this timer." + }, + "total-flaky-tests": { + "type": "number", + "format": "double", + "description": "A count of unique tests that have failed. If your project has N tests that have flaked multiple times each, this will be equal to N.", + "example": 5 + } + }, + "required": [ + "flaky-tests", + "total-flaky-tests" + ], + "description": "Flaky tests response" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/flaky-tests \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/flaky-tests';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/flaky-tests\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/flaky-tests\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/flaky-tests\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/workflows": { + "get": { + "summary": "Get summary metrics for a project's workflows", + "description": "Get summary metrics for a project's workflows. Workflow runs going back at most 90 days are included in the aggregation window. Metrics are refreshed daily, and thus may not include executions from the last 24 hours. Please note that Insights is not a financial reporting tool and should not be used for precise credit reporting. Credit reporting from Insights does not use the same source of truth as the billing information that is found in the Plan Overview page in the CircleCI UI, nor does the underlying data have the same data accuracy guarantees as the billing information in the CircleCI UI. This may lead to discrepancies between credits reported from Insights and the billing information in the Plan Overview page of the CircleCI UI. For precise credit reporting, always use the Plan Overview page in the CircleCI UI.", + "tags": [ + "Insights" + ], + "operationId": "getProjectWorkflowMetrics", + "responses": { + "200": { + "description": "A paginated list of summary metrics by workflow", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "metrics": { + "type": "object", + "properties": { + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "successful_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of successful runs." + }, + "mttr": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The mean time to recovery (mean time between failures and their next success) in seconds." + }, + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The total credits consumed by the workflow in the aggregation window. Note that Insights is not a real time financial reporting tool and should not be used for credit reporting." + }, + "failed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of failed runs." + }, + "success_rate": { + "type": "number", + "format": "float" + }, + "duration_metrics": { + "type": "object", + "properties": { + "min": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The minimum duration, in seconds, among a group of runs." + }, + "mean": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The mean duration, in seconds, among a group of runs." + }, + "median": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The median duration, in seconds, among a group of runs." + }, + "p95": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The 95th percentile duration, in seconds, among a group of runs." + }, + "max": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The max duration, in seconds, among a group of runs." + }, + "standard_deviation": { + "type": "number", + "format": "float", + "x-nullable": true, + "description": "The standard deviation, in seconds, among a group of runs." + } + }, + "required": [ + "min", + "mean", + "median", + "p95", + "max", + "standard_deviation" + ], + "description": "Metrics relating to the duration of runs for a workflow." + }, + "total_recoveries": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The number of recovered workflow executions per day." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "The average number of runs per day." + } + }, + "required": [ + "total_runs", + "successful_runs", + "mttr", + "total_credits_used", + "failed_runs", + "success_rate", + "duration_metrics", + "total_recoveries", + "throughput" + ], + "description": "Metrics relating to a workflow's runs." + }, + "window_start": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the first build within the requested reporting window." + }, + "window_end": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the last build within the requested reporting window." + }, + "project_id": { + "description": "The unique ID of the project" + } + }, + "required": [ + "name", + "metrics", + "window_start", + "window_end", + "project_id" + ] + }, + "description": "Workflow summary metrics." + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "Paginated workflow summary metrics." + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + }, + { + "in": "query", + "name": "all-branches", + "description": "Whether to retrieve data for all branches combined. Use either this parameter OR the branch name parameter.", + "schema": { + "type": "boolean" + }, + "required": false + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch. If not passed we will scope the API call to the default branch.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "in": "query", + "name": "reporting-window", + "description": "The time window used to calculate summary metrics. If not provided, defaults to last-90-days", + "schema": { + "type": "string" + }, + "required": false, + "example": "last-90-days" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/workflows/{workflow-name}": { + "get": { + "summary": "Get recent runs of a workflow", + "description": "Get recent runs of a workflow. Runs going back at most 90 days are returned. Please note that Insights is not a financial reporting tool and should not be used for precise credit reporting. Credit reporting from Insights does not use the same source of truth as the billing information that is found in the Plan Overview page in the CircleCI UI, nor does the underlying data have the same data accuracy guarantees as the billing information in the CircleCI UI. This may lead to discrepancies between credits reported from Insights and the billing information in the Plan Overview page of the CircleCI UI. For precise credit reporting, always use the Plan Overview page in the CircleCI UI.", + "tags": [ + "Insights" + ], + "operationId": "getProjectWorkflowRuns", + "responses": { + "200": { + "description": "A paginated list of recent workflow runs", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the workflow." + }, + "branch": { + "type": "string", + "description": "The VCS branch of a Workflow's trigger.", + "example": "main" + }, + "duration": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The duration in seconds of a run." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the workflow was created." + }, + "stopped_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "The date and time the workflow stopped." + }, + "credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of credits used during execution. Note that Insights is not a real time financial reporting tool and should not be used for credit reporting." + }, + "status": { + "type": "string", + "x-nullable": true, + "description": "Workflow status." + }, + "is_approval": { + "type": "boolean", + "description": "Describes if the job is an approval job or not. Approval jobs are intermediary jobs that are created to pause the workflow until approved.", + "example": false + } + }, + "required": [ + "id", + "branch", + "duration", + "created_at", + "stopped_at", + "credits_used", + "status", + "is_approval" + ] + }, + "description": "Recent workflow runs." + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "Paginated recent workflow runs." + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "workflow-name", + "description": "The name of the workflow.", + "schema": { + "type": "string" + }, + "required": true, + "example": "build-and-test" + }, + { + "in": "query", + "name": "all-branches", + "description": "Whether to retrieve data for all branches combined. Use either this parameter OR the branch name parameter.", + "schema": { + "type": "boolean" + }, + "required": false + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch. If not passed we will scope the API call to the default branch.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + }, + { + "in": "query", + "name": "start-date", + "description": "Include only executions that started at or after this date. This must be specified if an end-date is provided.", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-08-21T13:26:29Z" + }, + { + "in": "query", + "name": "end-date", + "description": "Include only executions that started before this date. This date can be at most 90 days after the start-date.", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-09-04T13:26:29Z" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test?all-branches=true&branch=example-value&page-token=example-value&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test?all-branches=true&branch=example-value&page-token=example-value&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test?all-branches=true&branch=example-value&page-token=example-value&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test?all-branches=true&branch=example-value&page-token=example-value&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test?all-branches=true&branch=example-value&page-token=example-value&start-date=2020-08-21T13%3A26%3A29Z&end-date=2020-09-04T13%3A26%3A29Z\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/workflows/{workflow-name}/jobs": { + "get": { + "summary": "Get summary metrics for a project workflow's jobs.", + "description": "Get summary metrics for a project workflow's jobs. Job runs going back at most 90 days are included in the aggregation window. Metrics are refreshed daily, and thus may not include executions from the last 24 hours. Please note that Insights is not a financial reporting tool and should not be used for precise credit reporting. Credit reporting from Insights does not use the same source of truth as the billing information that is found in the Plan Overview page in the CircleCI UI, nor does the underlying data have the same data accuracy guarantees as the billing information in the CircleCI UI. This may lead to discrepancies between credits reported from Insights and the billing information in the Plan Overview page of the CircleCI UI. For precise credit reporting, always use the Plan Overview page in the CircleCI UI.", + "tags": [ + "Insights" + ], + "operationId": "getProjectWorkflowJobMetrics", + "responses": { + "200": { + "description": "A paginated list of summary metrics by workflow job.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the job." + }, + "metrics": { + "type": "object", + "properties": { + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "failed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of failed runs." + }, + "successful_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of successful runs." + }, + "duration_metrics": { + "type": "object", + "properties": { + "min": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The minimum duration, in seconds, among a group of runs." + }, + "mean": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The mean duration, in seconds, among a group of runs." + }, + "median": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The median duration, in seconds, among a group of runs." + }, + "p95": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The 95th percentile duration, in seconds, among a group of runs." + }, + "max": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The max duration, in seconds, among a group of runs." + }, + "standard_deviation": { + "type": "number", + "format": "float", + "x-nullable": true, + "description": "The standard deviation, in seconds, among a group of runs." + } + }, + "required": [ + "min", + "mean", + "median", + "p95", + "max", + "standard_deviation" + ], + "description": "Metrics relating to the duration of runs for a workflow job." + }, + "success_rate": { + "type": "number", + "format": "float" + }, + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total credits consumed by the job in the aggregation window. Note that Insights is not a real time financial reporting tool and should not be used for credit reporting." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "The average number of runs per day." + } + }, + "required": [ + "total_runs", + "failed_runs", + "successful_runs", + "duration_metrics", + "success_rate", + "total_credits_used", + "throughput" + ], + "description": "Metrics relating to a workflow job's runs." + }, + "window_start": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the first build within the requested reporting window." + }, + "window_end": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the last build within the requested reporting window." + } + }, + "required": [ + "name", + "metrics", + "window_start", + "window_end" + ] + }, + "description": "Job summary metrics." + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "Paginated workflow job summary metrics." + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "workflow-name", + "description": "The name of the workflow.", + "schema": { + "type": "string" + }, + "required": true, + "example": "build-and-test" + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + }, + { + "in": "query", + "name": "all-branches", + "description": "Whether to retrieve data for all branches combined. Use either this parameter OR the branch name parameter.", + "schema": { + "type": "boolean" + }, + "required": false + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch. If not passed we will scope the API call to the default branch.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "in": "query", + "name": "reporting-window", + "description": "The time window used to calculate summary metrics. If not provided, defaults to last-90-days", + "schema": { + "type": "string" + }, + "required": false, + "example": "last-90-days" + }, + { + "in": "query", + "name": "job-name", + "description": "The name of the jobs you would like to filter from your workflow. If not specified, all workflow jobs will be returned. The job name can either be the full job name or just a substring of the job name.", + "schema": { + "type": "string" + }, + "required": false, + "example": "lint" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days&job-name=lint\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days&job-name=lint';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days&job-name=lint\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days&job-name=lint\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/jobs?page-token=example-value&all-branches=true&branch=example-value&reporting-window=last-90-days&job-name=lint\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/workflows/{workflow-name}/summary": { + "get": { + "summary": "Get metrics and trends for workflows", + "description": "Get the metrics and trends for a particular workflow on a single branch or all branches", + "tags": [ + "Insights" + ], + "operationId": "getWorkflowSummary", + "responses": { + "200": { + "description": "Metrics and trends for a workflow", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "metrics": { + "type": "object", + "properties": { + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of runs, including runs that are still on-hold or running." + }, + "successful_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of successful runs." + }, + "mttr": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The mean time to recovery (mean time between failures and their next success) in seconds." + }, + "total_credits_used": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The total credits consumed by the workflow in the aggregation window. Note that Insights is not a real time financial reporting tool and should not be used for credit reporting." + }, + "failed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of failed runs." + }, + "success_rate": { + "type": "number", + "format": "float" + }, + "completed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The number of runs that ran to completion within the aggregation window" + }, + "window_start": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the first build within the requested reporting window." + }, + "duration_metrics": { + "type": "object", + "properties": { + "min": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The minimum duration, in seconds, among a group of runs." + }, + "mean": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The mean duration, in seconds, among a group of runs." + }, + "median": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The median duration, in seconds, among a group of runs." + }, + "p95": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The 95th percentile duration, in seconds, among a group of runs." + }, + "max": { + "type": "integer", + "format": "int64", + "minimum": 0, + "x-nullable": true, + "description": "The max duration, in seconds, among a group of runs." + }, + "standard_deviation": { + "type": "number", + "format": "float", + "x-nullable": true, + "description": "The standard deviation, in seconds, among a group of runs." + } + }, + "required": [ + "min", + "mean", + "median", + "p95", + "max", + "standard_deviation" + ], + "description": "Metrics relating to the duration of runs for a workflow." + }, + "window_end": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the last build within the requested reporting window." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "The average number of runs per day." + } + }, + "required": [ + "total_runs", + "successful_runs", + "mttr", + "total_credits_used", + "failed_runs", + "success_rate", + "window_start", + "duration_metrics", + "window_end", + "throughput", + "completed_runs" + ], + "description": "Metrics aggregated across a workflow for a given time window." + }, + "trends": { + "type": "object", + "properties": { + "total_runs": { + "type": "number", + "format": "float", + "description": "The trend value for total number of runs." + }, + "failed_runs": { + "type": "number", + "format": "float", + "description": "The trend value for number of failed runs." + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The trend value for the success rate." + }, + "p95_duration_secs": { + "type": "number", + "format": "float", + "description": "Trend value for the 95th percentile duration for a workflow for a given time window." + }, + "median_duration_secs": { + "type": "number", + "format": "float", + "description": "Trend value for the 50th percentile duration for a workflow for a given time window." + }, + "total_credits_used": { + "type": "number", + "format": "float", + "description": "The trend value for total credits consumed." + }, + "mttr": { + "type": "number", + "format": "float", + "description": "trend for mean time to recovery (mean time between failures and their next success)." + }, + "throughput": { + "type": "number", + "format": "float", + "description": "Trend value for the average number of runs per day." + } + }, + "required": [ + "total_runs", + "failed_runs", + "success_rate", + "p95_duration_secs", + "median_duration_secs", + "total_credits_used", + "mttr", + "throughput" + ], + "description": "Trends for aggregated metrics across a workflow for a given time window." + }, + "workflow_names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of all the workflow names for a given project." + } + }, + "required": [ + "metrics", + "trends", + "workflow_names" + ], + "description": "Workflow level aggregated metrics and trends response" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "workflow-name", + "description": "The name of the workflow.", + "schema": { + "type": "string" + }, + "required": true, + "example": "build-and-test" + }, + { + "in": "query", + "name": "all-branches", + "description": "Whether to retrieve data for all branches combined. Use either this parameter OR the branch name parameter.", + "schema": { + "type": "boolean" + }, + "required": false + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch. If not passed we will scope the API call to the default branch.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/summary?all-branches=true&branch=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/summary?all-branches=true&branch=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/summary?all-branches=true&branch=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/summary?all-branches=true&branch=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/summary?all-branches=true&branch=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/insights/{project-slug}/workflows/{workflow-name}/test-metrics": { + "get": { + "summary": "Get test metrics for a project's workflows", + "description": "Get test metrics for a project's workflows. Currently tests metrics are calculated based on 10 most recent workflow runs.", + "tags": [ + "Insights" + ], + "operationId": "getProjectWorkflowTestMetrics", + "responses": { + "200": { + "description": "A list of test metrics by workflow", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "average_test_count": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The average number of tests executed per run" + }, + "most_failed_tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "p95_duration": { + "type": "number", + "format": "double", + "x-nullable": true, + "description": "The 95th percentile duration, in seconds, among a group of test runs." + }, + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of times the test was run." + }, + "classname": { + "type": "string", + "x-nullable": true, + "description": "The class the test belongs to." + }, + "failed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of times the test failed" + }, + "flaky": { + "type": "boolean", + "description": "Whether the test is flaky." + }, + "source": { + "type": "string", + "x-nullable": true, + "description": "The source of the test." + }, + "file": { + "type": "string", + "x-nullable": true, + "description": "The file the test belongs to." + }, + "job_name": { + "type": "string", + "description": "The name of the job." + }, + "test_name": { + "type": "string", + "description": "The name of the test." + } + }, + "required": [ + "failed_runs", + "job_name", + "p95_duration", + "test_name", + "file", + "source", + "classname", + "total_runs", + "flaky" + ] + }, + "description": "Metrics for the most frequently failing tests" + }, + "most_failed_tests_extra": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of tests with the same success rate being omitted from most_failed_tests" + }, + "slowest_tests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "p95_duration": { + "type": "number", + "format": "double", + "x-nullable": true, + "description": "The 95th percentile duration, in seconds, among a group of test runs." + }, + "total_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of times the test was run." + }, + "classname": { + "type": "string", + "x-nullable": true, + "description": "The class the test belongs to." + }, + "failed_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of times the test failed" + }, + "flaky": { + "type": "boolean", + "description": "Whether the test is flaky." + }, + "source": { + "type": "string", + "x-nullable": true, + "description": "The source of the test." + }, + "file": { + "type": "string", + "x-nullable": true, + "description": "The file the test belongs to." + }, + "job_name": { + "type": "string", + "description": "The name of the job." + }, + "test_name": { + "type": "string", + "description": "The name of the test." + } + }, + "required": [ + "failed_runs", + "job_name", + "p95_duration", + "test_name", + "file", + "source", + "classname", + "total_runs", + "flaky" + ] + }, + "description": "Metrics for the slowest running tests" + }, + "slowest_tests_extra": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of tests with the same duration rate being omitted from slowest_tests" + }, + "total_test_runs": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of test runs" + }, + "test_runs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pipeline_number": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of the pipeline associated with the provided test counts" + }, + "workflow_id": { + "description": "The ID of the workflow associated with the provided test counts" + }, + "success_rate": { + "type": "number", + "format": "float", + "description": "The success rate calculated from test counts" + }, + "test_counts": { + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of tests with the error status" + }, + "failure": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of tests with the failure status" + }, + "skipped": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of tests with the skipped status" + }, + "success": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The number of tests with the success status" + }, + "total": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The total number of tests" + } + }, + "required": [ + "error", + "failure", + "skipped", + "success", + "total" + ], + "description": "Test counts for a given pipeline number" + } + }, + "required": [ + "pipeline_number", + "workflow_id", + "success_rate", + "test_counts" + ] + }, + "description": "Test counts grouped by pipeline number and workflow id" + } + }, + "required": [ + "average_test_count", + "most_failed_tests", + "most_failed_tests_extra", + "slowest_tests", + "slowest_tests_extra", + "total_test_runs", + "test_runs" + ], + "description": "Project level test metrics response" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "workflow-name", + "description": "The name of the workflow.", + "schema": { + "type": "string" + }, + "required": true, + "example": "build-and-test" + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch. If not passed we will scope the API call to the default branch.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "in": "query", + "name": "all-branches", + "description": "Whether to retrieve data for all branches combined. Use either this parameter OR the branch name parameter.", + "schema": { + "type": "boolean" + }, + "required": false + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/test-metrics?branch=example-value&all-branches=true\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/test-metrics?branch=example-value&all-branches=true';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/test-metrics?branch=example-value&all-branches=true\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/test-metrics?branch=example-value&all-branches=true\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/insights/gh/CircleCI-Public/api-preview-docs/workflows/build-and-test/test-metrics?branch=example-value&all-branches=true\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/jobs/{job-id}/cancel": { + "post": { + "summary": "Cancel job by job ID", + "description": "Cancel job with a given job ID.", + "tags": [ + "Job" + ], + "operationId": "cancelJobByJobID", + "responses": { + "200": { + "description": "Job cancelled successfully.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "400": { + "description": "Bad request error.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "401": { + "description": "Unauthorized error.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "403": { + "description": "Forbidden error.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "404": { + "description": "Job not found error.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "job-id", + "description": "The unique ID of the job.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/jobs/497f6eca-6276-4993-bfeb-53cbbbba6f08/cancel \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/jobs/497f6eca-6276-4993-bfeb-53cbbbba6f08/cancel';\n const options = {method: 'POST', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"POST\", \"/api/v2/jobs/497f6eca-6276-4993-bfeb-53cbbbba6f08/cancel\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/jobs/497f6eca-6276-4993-bfeb-53cbbbba6f08/cancel\"\n\n\treq, _ := http.NewRequest(\"POST\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/jobs/497f6eca-6276-4993-bfeb-53cbbbba6f08/cancel\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/me": { + "get": { + "summary": "User Information", + "description": "Provides information about the user that is currently signed in.", + "tags": [ + "User" + ], + "operationId": "getCurrentUser", + "responses": { + "200": { + "description": "User login information.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "name": { + "type": "string", + "description": "The name of the user." + } + }, + "required": [ + "avatar_url", + "id", + "login", + "name" + ], + "title": "User" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/me \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/me';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/me\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/me\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/me\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/me/collaborations": { + "get": { + "summary": "Collaborations", + "description": "Provides the set of organizations of which a user is a member or a collaborator.\n\nThe set of organizations that a user can collaborate on is composed of:\n\n* Organizations that the current user belongs to across VCS types (e.g. BitBucket, GitHub)\n* The parent organization of repository that the user can collaborate on, but is not necessarily a member of\n* The organization of the current user's account", + "tags": [ + "User" + ], + "operationId": "getCollaborations", + "responses": { + "200": { + "description": "Collaborations", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "The UUID of the organization" + }, + "vcs-type": { + "type": "string", + "description": "The VCS provider" + }, + "name": { + "type": "string", + "description": "The name of the organization" + }, + "avatar_url": { + "type": "string", + "description": "URL to the user's avatar on the VCS" + }, + "slug": { + "type": "string", + "description": "The slug of the organization" + } + }, + "required": [ + "id", + "vcs-type", + "name", + "avatar_url", + "slug" + ], + "title": "Collaboration" + } + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/me/collaborations \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/me/collaborations';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/me/collaborations\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/me/collaborations\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/me/collaborations\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organization": { + "post": { + "summary": "Create a new organization", + "description": "Create a new organization. For VCS providers (GitHub/Bitbucket), this validates access and syncs org data. For standalone orgs, this creates a new CircleCI organization.", + "tags": [ + "Organization" + ], + "operationId": "createOrganization", + "responses": { + "201": { + "description": "The newly created organization", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique ID of the organization." + }, + "name": { + "type": "string", + "description": "The name of the organization." + }, + "slug": { + "type": "string", + "description": "Org slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings)." + }, + "vcs_type": { + "type": "string", + "description": "The version control system type for the organization.", + "example": "github" + } + }, + "required": [ + "id", + "name", + "slug", + "vcs_type" + ] + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the organization." + }, + "vcs_type": { + "type": "string", + "description": "The version control system type for the organization.", + "example": "github" + } + }, + "required": [ + "name", + "vcs_type" + ] + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/organization \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"example-string\\\",\n \\\"vcs_type\\\": \\\"github\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organization';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"example-string\",\"vcs_type\":\"github\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"vcs_type\\\": \\\"github\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/organization\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organization\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"vcs_type\\\": \\\"github\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organization\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"vcs_type\\\": \\\"github\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organization/{org-slug-or-id}": { + "delete": { + "summary": "Delete an organization", + "description": "Delete an organization. This action will delete all projects including all build data for the organization.", + "tags": [ + "Organization" + ], + "operationId": "deleteOrganization", + "responses": { + "202": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "org-slug-or-id", + "description": "Org UUID or slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/organization/gh/CircleCI-Public \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organization/gh/CircleCI-Public';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/organization/gh/CircleCI-Public\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organization/gh/CircleCI-Public\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organization/gh/CircleCI-Public\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organization/{org-slug-or-id}/project": { + "post": { + "summary": "Create a new project", + "description": "Create a new project. Works for all organization types.", + "tags": [ + "Project" + ], + "operationId": "createProject", + "responses": { + "200": { + "description": "The new project", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "name": { + "type": "string", + "description": "The name of the project", + "example": "api-preview-docs" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "organization_name": { + "type": "string", + "description": "The name of the organization the project belongs to", + "example": "CircleCI-Public" + }, + "organization_slug": { + "type": "string", + "description": "The slug of the organization the project belongs to", + "example": "gh/CircleCI-Public" + }, + "organization_id": { + "type": "string", + "format": "uuid", + "description": "The id of the organization the project belongs to", + "example": "ec6887ec-7d44-4b31-b468-7e552408ee32" + }, + "vcs_info": { + "type": "object", + "properties": { + "vcs_url": { + "type": "string", + "description": "URL to the repository hosting the project's code", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "provider": { + "type": "string", + "description": "The VCS provider" + }, + "default_branch": { + "type": "string", + "example": "main" + } + }, + "required": [ + "vcs_url", + "provider", + "default_branch" + ], + "description": "Information about the VCS that hosts the project source code." + } + }, + "required": [ + "slug", + "name", + "id", + "organization_name", + "organization_slug", + "organization_id", + "vcs_info" + ], + "description": "NOTE: The definition of Project is subject to change.", + "title": "Project" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "org-slug-or-id", + "description": "Org UUID or slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the project", + "example": "api-preview-docs" + } + }, + "required": [ + "name" + ] + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/organization/gh/CircleCI-Public/project \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"api-preview-docs\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organization/gh/CircleCI-Public/project';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"api-preview-docs\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"api-preview-docs\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/organization/gh/CircleCI-Public/project\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organization/gh/CircleCI-Public/project\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"api-preview-docs\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organization/gh/CircleCI-Public/project\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"api-preview-docs\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organization/{org-slug-or-id}/url-orb-allow-list": { + "post": { + "summary": "Create a new URL Orb allow-list entry", + "description": "Create a new URL Orb allow-list entry", + "tags": [ + "Organization" + ], + "operationId": "createURLOrbAllowListEntry", + "responses": { + "200": { + "description": "The ID of the new URL Orb allow-list entry", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "URL orb allow-list entry UUID.", + "example": "ba98990a-5a00-4cad-b55e-b44117b92e0c" + }, + "message": { + "type": "string", + "description": "Message describing the outcome of an operation", + "example": "Created." + } + }, + "required": [ + "id", + "message" + ] + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "org-slug-or-id", + "description": "Org UUID or slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the URL orb allow-list entry.", + "example": "Allow URL orbs from raw.githubusercontent.com/CircleCI-Public" + }, + "prefix": { + "description": "URL prefix. URL orb references that start with this prefix will be allowed by this allow-list entry.", + "example": "https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/" + }, + "auth": { + "type": "string", + "description": "An authentication method to use for fetching URL orb references that match this allow-list entry's prefix. Allowed values are \"bitbucket-oauth\", \"github-oauth\", \"github-app\", or \"none\".", + "example": "github-app" + } + }, + "required": [ + "name", + "prefix", + "auth" + ] + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"Allow URL orbs from raw.githubusercontent.com/CircleCI-Public\\\",\n \\\"prefix\\\": \\\"https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/\\\",\n \\\"auth\\\": \\\"github-app\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"Allow URL orbs from raw.githubusercontent.com/CircleCI-Public\",\"prefix\":\"https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/\",\"auth\":\"github-app\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"Allow URL orbs from raw.githubusercontent.com/CircleCI-Public\\\",\\n \\\"prefix\\\": \\\"https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/\\\",\\n \\\"auth\\\": \\\"github-app\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"Allow URL orbs from raw.githubusercontent.com/CircleCI-Public\\\",\\n \\\"prefix\\\": \\\"https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/\\\",\\n \\\"auth\\\": \\\"github-app\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"Allow URL orbs from raw.githubusercontent.com/CircleCI-Public\\\",\\n \\\"prefix\\\": \\\"https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/\\\",\\n \\\"auth\\\": \\\"github-app\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "List the entries in the org's URL Orb allow-list", + "description": "List the entries in the org's URL Orb allow-list", + "tags": [ + "Organization" + ], + "operationId": "listURLOrbAllowListEntries", + "responses": { + "200": { + "description": "URL Orb allow-list entries", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "URL orb allow-list entry UUID.", + "example": "ba98990a-5a00-4cad-b55e-b44117b92e0c" + }, + "name": { + "type": "string", + "description": "Name of the URL orb allow-list entry.", + "example": "Allow URL orbs from raw.githubusercontent.com/CircleCI-Public" + }, + "prefix": { + "description": "URL prefix. URL orb references that start with this prefix will be allowed by this allow-list entry.", + "example": "https://raw.githubusercontent.com/CircleCI-Public/orbs/refs/heads/main/" + }, + "auth": { + "type": "string", + "description": "An authentication method to use for fetching URL orb references that match this allow-list entry's prefix. Allowed values are \"bitbucket-oauth\", \"github-oauth\", \"github-app\", or \"none\".", + "example": "github-app" + } + }, + "required": [ + "id", + "name", + "prefix", + "auth" + ] + } + } + }, + "required": [ + "items" + ] + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "org-slug-or-id", + "description": "Org UUID or slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organization/{org-slug-or-id}/url-orb-allow-list/{allow-list-entry-id}": { + "delete": { + "summary": "Remove an entry from the org's URL orb allow-list", + "description": "Remove an entry from the org's URL orb allow-list", + "tags": [ + "Organization" + ], + "operationId": "removeURLOrbAllowListEntry", + "responses": { + "200": { + "description": "The ID of the removed URL Orb allow-list entry", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "URL orb allow-list entry UUID.", + "example": "ba98990a-5a00-4cad-b55e-b44117b92e0c" + }, + "message": { + "type": "string", + "description": "Message describing the outcome of an operation", + "example": "Created." + } + }, + "required": [ + "id", + "message" + ] + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "org-slug-or-id", + "description": "Org UUID or slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public" + }, + { + "in": "path", + "name": "allow-list-entry-id", + "description": "URL orb allow-list entry UUID.", + "schema": { + "type": "string" + }, + "required": true, + "example": "ba98990a-5a00-4cad-b55e-b44117b92e0c" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list/ba98990a-5a00-4cad-b55e-b44117b92e0c \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list/ba98990a-5a00-4cad-b55e-b44117b92e0c';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list/ba98990a-5a00-4cad-b55e-b44117b92e0c\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list/ba98990a-5a00-4cad-b55e-b44117b92e0c\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organization/gh/CircleCI-Public/url-orb-allow-list/ba98990a-5a00-4cad-b55e-b44117b92e0c\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/pipeline": { + "get": { + "summary": "Get a list of pipelines", + "description": "Returns all pipelines for the most recently built projects (max 250) you follow in an organization.", + "tags": [ + "Pipeline" + ], + "operationId": "listPipelines", + "responses": { + "200": { + "description": "A sequence of pipelines.", + "links": { + "NextPipelinePage": { + "operationId": "listPipelines", + "parameters": { + "page-token": "$response.body#/next_page_token" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of error." + }, + "message": { + "type": "string", + "description": "A human-readable error message." + } + }, + "required": [ + "type", + "message" + ], + "description": "An error with a type and message." + }, + "description": "A sequence of errors that have occurred within the pipeline." + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline.", + "example": 25 + }, + "trigger_parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + } + }, + "state": { + "type": "string", + "description": "The current state of the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "trigger": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of trigger." + }, + "received_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was received." + }, + "actor": { + "type": "object", + "properties": { + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + } + }, + "required": [ + "login", + "avatar_url" + ], + "description": "The user who triggered the Pipeline." + } + }, + "required": [ + "type", + "received_at", + "actor" + ], + "description": "A summary of the trigger." + }, + "vcs": { + "type": "object", + "properties": { + "provider_name": { + "type": "string", + "description": "Name of the VCS provider (e.g. GitHub, Bitbucket).", + "example": "GitHub" + }, + "target_repository_url": { + "type": "string", + "description": "URL for the repository the trigger targets (i.e. the repository where the PR will be merged). For fork-PR pipelines, this is the URL to the parent repo. For other pipelines, the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "branch": { + "type": "string", + "description": "The branch where the pipeline ran. The HEAD commit on this branch was used for the pipeline. Note that `branch` and `tag` are mutually exclusive. To trigger a pipeline for a PR by number use `pull//head` for the PR ref or `pull//merge` for the merge ref (GitHub only).", + "example": "feature/design-new-api" + }, + "review_id": { + "type": "string", + "description": "The code review id.", + "example": "123" + }, + "review_url": { + "type": "string", + "description": "The code review URL.", + "example": "https://github.com/CircleCI-Public/api-preview-docs/pull/123" + }, + "revision": { + "type": "string", + "x-nullable": true, + "description": "The code revision the pipeline ran.", + "example": "f454a02b5d10fcccfd7d9dd7608a76d6493a98b4" + }, + "tag": { + "type": "string", + "description": "The tag used by the pipeline. The commit that this tag points to was used for the pipeline. Note that `branch` and `tag` are mutually exclusive.", + "example": "v3.1.4159" + }, + "commit": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "x-nullable": true, + "description": "The subject of the commit message." + }, + "body": { + "type": "string", + "x-nullable": true, + "description": "The body of the commit message." + } + }, + "required": [ + "subject", + "body" + ], + "description": "The latest commit in the pipeline." + }, + "origin_repository_url": { + "type": "string", + "description": "URL for the repository where the trigger originated. For fork-PR pipelines, this is the URL to the fork. For other pipelines the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + } + }, + "required": [ + "provider_name", + "origin_repository_url", + "target_repository_url", + "revision" + ], + "description": "VCS information for the pipeline." + } + }, + "required": [ + "id", + "number", + "project_slug", + "created_at", + "errors", + "state", + "trigger" + ], + "description": "A pipeline response.", + "title": "Pipeline" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "List of pipelines", + "title": "PipelineListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "query", + "name": "org-slug", + "description": "Org slug in the form `vcs-slug/org-name`. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug` and replace the `org-name` with the organization ID (found in Organization Settings).", + "schema": { + "type": "string" + }, + "required": false, + "example": "gh/CircleCI-Public" + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + }, + { + "in": "query", + "name": "mine", + "description": "Only include entries created by your user.", + "schema": { + "type": "boolean" + }, + "required": false + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/pipeline?org-slug=gh%2FCircleCI-Public&page-token=example-value&mine=true\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/pipeline?org-slug=gh%2FCircleCI-Public&page-token=example-value&mine=true';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/pipeline?org-slug=gh%2FCircleCI-Public&page-token=example-value&mine=true\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/pipeline?org-slug=gh%2FCircleCI-Public&page-token=example-value&mine=true\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/pipeline?org-slug=gh%2FCircleCI-Public&page-token=example-value&mine=true\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/pipeline/continue": { + "post": { + "summary": "Continue a pipeline", + "description": "Continue a pipeline from the setup phase. For information on using pipeline parameters with dynamic configuration, see the [Pipeline values and parameters](https://circleci.com/docs/pipeline-variables/#pipeline-parameters-and-dynamic-configuration) docs.", + "tags": [ + "Pipeline" + ], + "operationId": "continuePipeline", + "responses": { + "200": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "continuation-key": { + "type": "string", + "description": "A pipeline continuation key.", + "title": "PipelineContinuationKey" + }, + "configuration": { + "type": "string", + "description": "A configuration string for the pipeline." + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "An object containing pipeline parameters and their values. Pipeline parameters have the following size limits: 100 max entries, 128 maximum key length, 512 maximum value length.", + "example": { + "deploy_prod": true + } + } + }, + "required": [ + "continuation-key", + "configuration" + ] + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/pipeline/continue \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"continuation-key\\\": \\\"example-string\\\",\n \\\"configuration\\\": \\\"example-string\\\",\n \\\"parameters\\\": {\n \\\"deploy_prod\\\": true\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/pipeline/continue';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"continuation-key\":\"example-string\",\"configuration\":\"example-string\",\"parameters\":{\"deploy_prod\":true}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"continuation-key\\\": \\\"example-string\\\",\\n \\\"configuration\\\": \\\"example-string\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/pipeline/continue\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/pipeline/continue\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"continuation-key\\\": \\\"example-string\\\",\\n \\\"configuration\\\": \\\"example-string\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/pipeline/continue\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"continuation-key\\\": \\\"example-string\\\",\\n \\\"configuration\\\": \\\"example-string\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/pipeline/{pipeline-id}": { + "get": { + "summary": "Get a pipeline by ID", + "description": "Returns a pipeline by the pipeline ID.", + "tags": [ + "Pipeline" + ], + "operationId": "getPipelineById", + "responses": { + "200": { + "description": "A pipeline object.", + "links": { + "ProjectFromPipeline": { + "operationId": "getProjectBySlug", + "parameters": { + "project_slug": "$response.body#/project_slug" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of error." + }, + "message": { + "type": "string", + "description": "A human-readable error message." + } + }, + "required": [ + "type", + "message" + ], + "description": "An error with a type and message." + }, + "description": "A sequence of errors that have occurred within the pipeline." + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline.", + "example": 25 + }, + "trigger_parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + } + }, + "state": { + "type": "string", + "description": "The current state of the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "trigger": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of trigger." + }, + "received_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was received." + }, + "actor": { + "type": "object", + "properties": { + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + } + }, + "required": [ + "login", + "avatar_url" + ], + "description": "The user who triggered the Pipeline." + } + }, + "required": [ + "type", + "received_at", + "actor" + ], + "description": "A summary of the trigger." + }, + "vcs": { + "type": "object", + "properties": { + "provider_name": { + "type": "string", + "description": "Name of the VCS provider (e.g. GitHub, Bitbucket).", + "example": "GitHub" + }, + "target_repository_url": { + "type": "string", + "description": "URL for the repository the trigger targets (i.e. the repository where the PR will be merged). For fork-PR pipelines, this is the URL to the parent repo. For other pipelines, the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "branch": { + "type": "string", + "description": "The branch where the pipeline ran. The HEAD commit on this branch was used for the pipeline. Note that `branch` and `tag` are mutually exclusive. To trigger a pipeline for a PR by number use `pull//head` for the PR ref or `pull//merge` for the merge ref (GitHub only).", + "example": "feature/design-new-api" + }, + "review_id": { + "type": "string", + "description": "The code review id.", + "example": "123" + }, + "review_url": { + "type": "string", + "description": "The code review URL.", + "example": "https://github.com/CircleCI-Public/api-preview-docs/pull/123" + }, + "revision": { + "type": "string", + "x-nullable": true, + "description": "The code revision the pipeline ran.", + "example": "f454a02b5d10fcccfd7d9dd7608a76d6493a98b4" + }, + "tag": { + "type": "string", + "description": "The tag used by the pipeline. The commit that this tag points to was used for the pipeline. Note that `branch` and `tag` are mutually exclusive.", + "example": "v3.1.4159" + }, + "commit": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "x-nullable": true, + "description": "The subject of the commit message." + }, + "body": { + "type": "string", + "x-nullable": true, + "description": "The body of the commit message." + } + }, + "required": [ + "subject", + "body" + ], + "description": "The latest commit in the pipeline." + }, + "origin_repository_url": { + "type": "string", + "description": "URL for the repository where the trigger originated. For fork-PR pipelines, this is the URL to the fork. For other pipelines the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + } + }, + "required": [ + "provider_name", + "origin_repository_url", + "target_repository_url", + "revision" + ], + "description": "VCS information for the pipeline." + } + }, + "required": [ + "id", + "number", + "project_slug", + "created_at", + "errors", + "state", + "trigger" + ], + "description": "A pipeline response.", + "title": "Pipeline" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "pipeline-id", + "description": "The unique ID of the pipeline.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/pipeline/{pipeline-id}/config": { + "get": { + "summary": "Get a pipeline's configuration", + "description": "Returns a pipeline's configuration by ID.", + "tags": [ + "Pipeline" + ], + "operationId": "getPipelineConfigById", + "responses": { + "200": { + "description": "The configuration strings for the pipeline.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "The source configuration for the pipeline, before any config compilation has been performed. If there is no config, then this field will be empty." + }, + "compiled": { + "type": "string", + "description": "The compiled configuration for the pipeline, after all orb expansion has been performed. If there were errors processing the pipeline's configuration, then this field may be empty." + }, + "setup-config": { + "type": "string", + "description": "The setup configuration for the pipeline used for Setup Workflows. If there were errors processing the pipeline's configuration or if setup workflows are not enabled, then this field should not exist" + }, + "compiled-setup-config": { + "type": "string", + "description": "The compiled setup configuration for the pipeline, after all orb expansion has been performed. If there were errors processing the pipeline's setup workflows, then this field may be empty." + } + }, + "required": [ + "source", + "compiled" + ], + "description": "The configuration strings for the pipeline.", + "title": "PipelineConfig" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "pipeline-id", + "description": "The unique ID of the pipeline.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/config \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/config';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/config\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/config\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/config\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/pipeline/{pipeline-id}/values": { + "get": { + "summary": "Get pipeline values for a pipeline", + "description": "Returns a map of pipeline values by pipeline ID. For more information see the [pipeline values reference page](https://circleci.com/docs/variables/#pipeline-values).", + "tags": [ + "Pipeline" + ], + "operationId": "getPipelineValuesById", + "responses": { + "200": { + "description": "A JSON object of pipeline values", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "boolean" + } + ] + }, + "description": "The pipeline-values for the pipeline.", + "title": "PipelineValues" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "pipeline-id", + "description": "The unique ID of the pipeline.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/values \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/values';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/values\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/values\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/values\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/pipeline/{pipeline-id}/workflow": { + "get": { + "summary": "Get a pipeline's workflows", + "description": "Returns a paginated list of workflows by pipeline ID.", + "tags": [ + "Pipeline" + ], + "operationId": "listWorkflowsByPipelineId", + "responses": { + "200": { + "description": "A paginated list of workflow objects.", + "links": { + "NextPipelineWorkflowsPage": { + "operationId": "listWorkflowsByPipelineId", + "parameters": { + "pipeline-id": "$request.path.pipeline-id", + "page-token": "$response.body#/next_page_token" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pipeline_id": { + "type": "string", + "format": "uuid", + "description": "The ID of the pipeline this workflow belongs to.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "canceled_by": { + "type": "string", + "format": "uuid" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the workflow." + }, + "auto_rerun_number": { + "type": "integer", + "format": "int64", + "minimum": 1, + "description": "Present if this workflow was auto-rerun from a previous workflow. The Nth auto-rerun workflow will have auto_rerun_number N", + "example": 1 + }, + "name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline this workflow belongs to.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "errored_by": { + "type": "string", + "format": "uuid" + }, + "tag": { + "type": "string", + "x-nullable": true, + "description": "Tag used for the workflow", + "example": "setup" + }, + "status": { + "type": "string", + "description": "The current status of the workflow." + }, + "started_by": { + "type": "string", + "format": "uuid" + }, + "max_auto_reruns": { + "type": "integer", + "format": "int64", + "minimum": 1, + "description": "The maximum number of auto reruns specified for the workflow.", + "example": 5 + }, + "pipeline_number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline this workflow belongs to.", + "example": 25 + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the workflow was created." + }, + "stopped_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "The date and time the workflow stopped." + } + }, + "required": [ + "id", + "name", + "status", + "created_at", + "stopped_at", + "pipeline_id", + "pipeline_number", + "project_slug", + "started_by" + ], + "description": "A workflow", + "title": "Workflow" + }, + "description": "A list of workflows.", + "title": "Workflow list" + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "A list of workflows and associated pagination token.", + "title": "WorkflowListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "pipeline-id", + "description": "The unique ID of the pipeline.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/workflow?page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/workflow?page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/workflow?page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/workflow?page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/pipeline/5034460f-c7c4-4c43-9457-de07e2029e7b/workflow?page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}": { + "get": { + "summary": "Get a project", + "description": "Retrieves a project by project slug.", + "tags": [ + "Project" + ], + "operationId": "getProjectBySlug", + "responses": { + "200": { + "description": "A project object", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "slug": { + "type": "string", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "name": { + "type": "string", + "description": "The name of the project", + "example": "api-preview-docs" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "organization_name": { + "type": "string", + "description": "The name of the organization the project belongs to", + "example": "CircleCI-Public" + }, + "organization_slug": { + "type": "string", + "description": "The slug of the organization the project belongs to", + "example": "gh/CircleCI-Public" + }, + "organization_id": { + "type": "string", + "format": "uuid", + "description": "The id of the organization the project belongs to", + "example": "ec6887ec-7d44-4b31-b468-7e552408ee32" + }, + "vcs_info": { + "type": "object", + "properties": { + "vcs_url": { + "type": "string", + "description": "URL to the repository hosting the project's code", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "provider": { + "type": "string", + "description": "The VCS provider" + }, + "default_branch": { + "type": "string", + "example": "main" + } + }, + "required": [ + "vcs_url", + "provider", + "default_branch" + ], + "description": "Information about the VCS that hosts the project source code." + } + }, + "required": [ + "slug", + "name", + "id", + "organization_name", + "organization_slug", + "organization_id", + "vcs_info" + ], + "description": "NOTE: The definition of Project is subject to change.", + "title": "Project" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Delete a project", + "description": "Deletes a project by project slug", + "tags": [ + "Project" + ], + "operationId": "deleteProjectBySlug", + "responses": { + "200": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/checkout-key": { + "get": { + "summary": "Get all checkout keys", + "description": "Returns a sequence of checkout keys for `:project`.", + "tags": [ + "Project" + ], + "operationId": "listCheckoutKeys", + "responses": { + "200": { + "description": "A sequence of checkout keys.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "public-key": { + "type": "string", + "description": "A public SSH key.", + "example": "ssh-rsa ..." + }, + "type": { + "type": "string", + "description": "The type of checkout key. This may be either `deploy-key` or `github-user-key`.", + "title": "CheckoutKeyType", + "example": "deploy-key" + }, + "fingerprint": { + "type": "string", + "description": "An SSH key fingerprint.", + "example": "c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f" + }, + "preferred": { + "type": "boolean", + "description": "A boolean value that indicates if this key is preferred.", + "example": true + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the checkout key was created.", + "example": "2015-09-21T17:29:21.042Z" + } + }, + "required": [ + "public-key", + "type", + "fingerprint", + "preferred", + "created-at" + ], + "description": "A checkout key", + "title": "CheckoutKey" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "title": "CheckoutKeyListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "digest", + "description": "The fingerprint digest type to return. This may be either `md5` or `sha256`. If not passed, defaults to `md5`.", + "schema": { + "type": "string" + }, + "required": false + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key?digest=sha256\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key?digest=sha256';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key?digest=sha256\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key?digest=sha256\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key?digest=sha256\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "summary": "Create a new checkout key", + "description": "Not available to projects that use GitLab or GitHub App. Creates a new checkout key. This API request is only usable with a user API token.\n Please ensure that you have authorized your account with GitHub before creating user keys.\n This is necessary to give CircleCI the permission to create a user key associated with\n your GitHub user account. You can find this page by visiting Project Settings > Checkout SSH Keys", + "tags": [ + "Project" + ], + "operationId": "createCheckoutKey", + "responses": { + "201": { + "description": "The checkout key.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "public-key": { + "type": "string", + "description": "A public SSH key.", + "example": "ssh-rsa ..." + }, + "type": { + "type": "string", + "description": "The type of checkout key. This may be either `deploy-key` or `github-user-key`.", + "title": "CheckoutKeyType", + "example": "deploy-key" + }, + "fingerprint": { + "type": "string", + "description": "An SSH key fingerprint.", + "example": "c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f" + }, + "preferred": { + "type": "boolean", + "description": "A boolean value that indicates if this key is preferred.", + "example": true + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the checkout key was created.", + "example": "2015-09-21T17:29:21.042Z" + } + }, + "required": [ + "public-key", + "type", + "fingerprint", + "preferred", + "created-at" + ], + "description": "A checkout key", + "title": "CheckoutKey" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of checkout key to create. This may be either `deploy-key` or `user-key`.", + "title": "CheckoutKeyInputType", + "example": "deploy-key" + } + }, + "required": [ + "type" + ], + "title": "CheckoutKeyInput" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"type\\\": \\\"deploy-key\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"type\":\"deploy-key\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"type\\\": \\\"deploy-key\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"type\\\": \\\"deploy-key\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"type\\\": \\\"deploy-key\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/checkout-key/{fingerprint}": { + "get": { + "summary": "Get a checkout key", + "description": "Returns an individual checkout key via md5 or sha256 fingerprint. sha256 keys should be url-encoded.", + "tags": [ + "Project" + ], + "operationId": "getCheckoutKey", + "responses": { + "200": { + "description": "The checkout key.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "public-key": { + "type": "string", + "description": "A public SSH key.", + "example": "ssh-rsa ..." + }, + "type": { + "type": "string", + "description": "The type of checkout key. This may be either `deploy-key` or `github-user-key`.", + "title": "CheckoutKeyType", + "example": "deploy-key" + }, + "fingerprint": { + "type": "string", + "description": "An SSH key fingerprint.", + "example": "c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f" + }, + "preferred": { + "type": "boolean", + "description": "A boolean value that indicates if this key is preferred.", + "example": true + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the checkout key was created.", + "example": "2015-09-21T17:29:21.042Z" + } + }, + "required": [ + "public-key", + "type", + "fingerprint", + "preferred", + "created-at" + ], + "description": "A checkout key", + "title": "CheckoutKey" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "fingerprint", + "description": "An SSH key fingerprint.", + "schema": { + "type": "string" + }, + "required": true, + "example": "c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Delete a checkout key", + "description": "Deletes the checkout key via md5 or sha256 fingerprint. sha256 keys should be url-encoded.", + "tags": [ + "Project" + ], + "operationId": "deleteCheckoutKey", + "responses": { + "200": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "fingerprint", + "description": "An SSH key fingerprint.", + "schema": { + "type": "string" + }, + "required": true, + "example": "c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/checkout-key/c9:0b:1c:4f:d5:65:56:b9:ad:88:f9:81:2b:37:74:2f\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/envvar": { + "get": { + "summary": "List all environment variables", + "description": "Returns four 'x' characters, in addition to the last four ASCII characters of the value, consistent with the display of environment variable values on the CircleCI website.", + "tags": [ + "Project" + ], + "operationId": "listEnvVars", + "responses": { + "200": { + "description": "A sequence of environment variables.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the environment variable.", + "example": "foo" + }, + "value": { + "type": "string", + "description": "The value of the environment variable.", + "example": "xxxx1234" + }, + "created-at": { + "x-nullable": true, + "description": "The creation timestamp of the environment variable.", + "example": "#joda/inst 2023-04-14T21:20:14+0000" + } + }, + "required": [ + "name", + "value" + ], + "description": "An environment variable is a map containing a value and an optional timestamp.", + "title": "EnvironmentVariable" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "title": "EnvironmentVariableListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "summary": "Create an environment variable", + "description": "Creates a new environment variable.", + "tags": [ + "Project" + ], + "operationId": "createEnvVar", + "responses": { + "201": { + "description": "The environment variable.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the environment variable.", + "example": "foo" + }, + "value": { + "type": "string", + "description": "The value of the environment variable.", + "example": "xxxx1234" + }, + "created-at": { + "x-nullable": true, + "description": "The creation timestamp of the environment variable.", + "example": "#joda/inst 2023-04-14T21:20:14+0000" + } + }, + "required": [ + "name", + "value" + ], + "description": "An environment variable is a map containing a value and an optional timestamp.", + "title": "EnvironmentVariable" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the environment variable.", + "example": "foo" + }, + "value": { + "type": "string", + "description": "The value of the environment variable.", + "example": "xxxx1234" + } + }, + "required": [ + "name", + "value" + ], + "description": "An environment variable request requires a name and a value", + "title": "EnvironmentVariable" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"foo\\\",\n \\\"value\\\": \\\"xxxx1234\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"foo\",\"value\":\"xxxx1234\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"foo\\\",\\n \\\"value\\\": \\\"xxxx1234\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"foo\\\",\\n \\\"value\\\": \\\"xxxx1234\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"foo\\\",\\n \\\"value\\\": \\\"xxxx1234\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/envvar/{name}": { + "get": { + "summary": "Get a masked environment variable", + "description": "Returns the masked value of environment variable :name.", + "tags": [ + "Project" + ], + "operationId": "getEnvVar", + "responses": { + "200": { + "description": "The environment variable.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the environment variable.", + "example": "foo" + }, + "value": { + "type": "string", + "description": "The value of the environment variable.", + "example": "xxxx1234" + }, + "created-at": { + "x-nullable": true, + "description": "The creation timestamp of the environment variable.", + "example": "#joda/inst 2023-04-14T21:20:14+0000" + } + }, + "required": [ + "name", + "value" + ], + "description": "An environment variable is a map containing a value and an optional timestamp.", + "title": "EnvironmentVariable" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "name", + "description": "The name of the environment variable.", + "schema": { + "type": "string" + }, + "required": true, + "example": "foo" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Delete an environment variable", + "description": "Deletes the environment variable named :name.", + "tags": [ + "Project" + ], + "operationId": "deleteEnvVar", + "responses": { + "200": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "name", + "description": "The name of the environment variable.", + "schema": { + "type": "string" + }, + "required": true, + "example": "foo" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/envvar/foo\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/job/{job-number}": { + "get": { + "summary": "Get job details", + "description": "Returns job details.", + "tags": [ + "Job" + ], + "operationId": "getJobDetails", + "responses": { + "200": { + "description": "Job details.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "web_url": { + "type": "string", + "description": "URL of the job in CircleCI Web UI." + }, + "project": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "slug": { + "type": "string", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "name": { + "type": "string", + "description": "The name of the project", + "example": "api-preview-docs" + }, + "external_url": { + "type": "string", + "description": "URL to the repository hosting the project's code", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + } + }, + "required": [ + "id", + "slug", + "name", + "external_url" + ], + "description": "Information about a project." + }, + "parallel_runs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "index": { + "type": "integer", + "format": "int64", + "description": "Index of the parallel run." + }, + "status": { + "type": "string", + "description": "Status of the parallel run." + } + }, + "required": [ + "index", + "status" + ], + "description": "Info about a status of the parallel run." + }, + "description": "Info about parallels runs and their status." + }, + "started_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the job started." + }, + "latest_workflow": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the workflow." + }, + "name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + } + }, + "required": [ + "id", + "name" + ], + "description": "Info about the latest workflow the job was a part of." + }, + "name": { + "type": "string", + "description": "The name of the job." + }, + "executor": { + "type": "object", + "properties": { + "resource_class": { + "type": "string", + "description": "Resource class name." + }, + "type": { + "type": "string", + "description": "Executor type." + } + }, + "required": [ + "resource_class" + ], + "description": "Information about executor used for a job." + }, + "parallelism": { + "type": "integer", + "format": "int64", + "description": "A number of parallel runs the job has." + }, + "status": { + "type": "string", + "description": "The current status of the job." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the job.", + "example": 1 + }, + "pipeline": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + }, + "required": [ + "id" + ], + "description": "Info about a pipeline the job is a part of." + }, + "duration": { + "type": "integer", + "format": "int64", + "x-nullable": true, + "description": "Duration of a job in milliseconds." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The time when the job was created." + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Message type." + }, + "message": { + "type": "string", + "description": "Information describing message." + }, + "reason": { + "type": "string", + "description": "Value describing the reason for message to be added to the job." + } + }, + "required": [ + "type", + "message" + ], + "description": "Message from CircleCI execution platform." + }, + "description": "Messages from CircleCI execution platform." + }, + "contexts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the context." + } + }, + "required": [ + "name" + ], + "description": "Information about the context." + }, + "description": "List of contexts used by the job." + }, + "organization": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the organization." + } + }, + "required": [ + "name" + ], + "description": "Information about an organization." + }, + "queued_at": { + "type": "string", + "format": "date-time", + "description": "The time when the job was placed in a queue." + }, + "stopped_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "The time when the job stopped." + } + }, + "required": [ + "number", + "name", + "status", + "started_at", + "created_at", + "queued_at", + "duration", + "executor", + "project", + "organization", + "contexts", + "web_url", + "parallel_runs", + "latest_workflow", + "pipeline", + "parallelism", + "messages" + ], + "description": "Job Details", + "title": "Job Details" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "job-number", + "description": "The number of the job.", + "schema": {}, + "required": true, + "example": "123" + }, + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/job/{job-number}/cancel": { + "post": { + "summary": "Cancel job by job number", + "description": "Cancel job with a given job number.", + "tags": [ + "Job" + ], + "operationId": "cancelJobByJobNumber", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + }, + "description": "" + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "job-number", + "description": "The number of the job.", + "schema": {}, + "required": true, + "example": "123" + }, + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123/cancel \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123/cancel';\n const options = {method: 'POST', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123/cancel\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123/cancel\"\n\n\treq, _ := http.NewRequest(\"POST\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/job/123/cancel\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/pipeline": { + "post": { + "summary": "Trigger a new pipeline", + "description": "**[This endpoint is superseded by the [new Trigger Pipeline API](#tag/Pipeline/operation/triggerPipelineRun), which supports all organization and pipeline types except GitLab.]** Triggers a new pipeline on the project. Does not support triggering pipelines integrated with GitLab or GitHub App.", + "tags": [ + "Pipeline" + ], + "operationId": "triggerPipeline", + "responses": { + "201": { + "description": "The created pipeline.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "state": { + "type": "string", + "description": "The current state of the pipeline." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline.", + "example": 25 + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + } + }, + "required": [ + "id", + "state", + "number", + "created_at" + ], + "description": "A pipeline creation response.", + "title": "PipelineCreation" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "branch": { + "type": "string", + "description": "The branch where the pipeline ran. The HEAD commit on this branch was used for the pipeline. Note that `branch` and `tag` are mutually exclusive. To trigger a pipeline for a PR by number use `pull//head` for the PR ref or `pull//merge` for the merge ref (GitHub only).", + "example": "feature/design-new-api" + }, + "tag": { + "type": "string", + "description": "The tag used by the pipeline. The commit that this tag points to was used for the pipeline. Note that `branch` and `tag` are mutually exclusive.", + "example": "v3.1.4159" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "An object containing pipeline parameters and their values. Pipeline parameters have the following size limits: 100 max entries, 128 maximum key length, 512 maximum value length.", + "example": { + "deploy_prod": true + } + } + }, + "x-nullable": true, + "description": "The information you can supply when triggering a pipeline.", + "title": "TriggerPipelineParameters" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"branch\\\": \\\"feature/design-new-api\\\",\n \\\"tag\\\": \\\"v3.1.4159\\\",\n \\\"parameters\\\": {\n \\\"deploy_prod\\\": true\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"branch\":\"feature/design-new-api\",\"tag\":\"v3.1.4159\",\"parameters\":{\"deploy_prod\":true}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"branch\\\": \\\"feature/design-new-api\\\",\\n \\\"tag\\\": \\\"v3.1.4159\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"branch\\\": \\\"feature/design-new-api\\\",\\n \\\"tag\\\": \\\"v3.1.4159\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"branch\\\": \\\"feature/design-new-api\\\",\\n \\\"tag\\\": \\\"v3.1.4159\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "Get all pipelines", + "description": "Returns all pipelines for this project.", + "tags": [ + "Pipeline" + ], + "operationId": "listPipelinesForProject", + "responses": { + "200": { + "description": "A sequence of pipelines.", + "links": { + "NextPipelinePage": { + "operationId": "listPipelinesForProject", + "parameters": { + "project-slug": "$request.path.project-slug", + "page-token": "$response.body#/next_page_token" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of error." + }, + "message": { + "type": "string", + "description": "A human-readable error message." + } + }, + "required": [ + "type", + "message" + ], + "description": "An error with a type and message." + }, + "description": "A sequence of errors that have occurred within the pipeline." + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline.", + "example": 25 + }, + "trigger_parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + } + }, + "state": { + "type": "string", + "description": "The current state of the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "trigger": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of trigger." + }, + "received_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was received." + }, + "actor": { + "type": "object", + "properties": { + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + } + }, + "required": [ + "login", + "avatar_url" + ], + "description": "The user who triggered the Pipeline." + } + }, + "required": [ + "type", + "received_at", + "actor" + ], + "description": "A summary of the trigger." + }, + "vcs": { + "type": "object", + "properties": { + "provider_name": { + "type": "string", + "description": "Name of the VCS provider (e.g. GitHub, Bitbucket).", + "example": "GitHub" + }, + "target_repository_url": { + "type": "string", + "description": "URL for the repository the trigger targets (i.e. the repository where the PR will be merged). For fork-PR pipelines, this is the URL to the parent repo. For other pipelines, the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "branch": { + "type": "string", + "description": "The branch where the pipeline ran. The HEAD commit on this branch was used for the pipeline. Note that `branch` and `tag` are mutually exclusive. To trigger a pipeline for a PR by number use `pull//head` for the PR ref or `pull//merge` for the merge ref (GitHub only).", + "example": "feature/design-new-api" + }, + "review_id": { + "type": "string", + "description": "The code review id.", + "example": "123" + }, + "review_url": { + "type": "string", + "description": "The code review URL.", + "example": "https://github.com/CircleCI-Public/api-preview-docs/pull/123" + }, + "revision": { + "type": "string", + "x-nullable": true, + "description": "The code revision the pipeline ran.", + "example": "f454a02b5d10fcccfd7d9dd7608a76d6493a98b4" + }, + "tag": { + "type": "string", + "description": "The tag used by the pipeline. The commit that this tag points to was used for the pipeline. Note that `branch` and `tag` are mutually exclusive.", + "example": "v3.1.4159" + }, + "commit": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "x-nullable": true, + "description": "The subject of the commit message." + }, + "body": { + "type": "string", + "x-nullable": true, + "description": "The body of the commit message." + } + }, + "required": [ + "subject", + "body" + ], + "description": "The latest commit in the pipeline." + }, + "origin_repository_url": { + "type": "string", + "description": "URL for the repository where the trigger originated. For fork-PR pipelines, this is the URL to the fork. For other pipelines the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + } + }, + "required": [ + "provider_name", + "origin_repository_url", + "target_repository_url", + "revision" + ], + "description": "VCS information for the pipeline." + } + }, + "required": [ + "id", + "number", + "project_slug", + "created_at", + "errors", + "state", + "trigger" + ], + "description": "A pipeline response.", + "title": "Pipeline" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "List of pipelines", + "title": "PipelineListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "branch", + "description": "The name of a vcs branch.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline?branch=example-value&page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline?branch=example-value&page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline?branch=example-value&page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline?branch=example-value&page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline?branch=example-value&page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/pipeline/mine": { + "get": { + "summary": "Get your pipelines", + "description": "Returns a sequence of all pipelines for this project triggered by the user.", + "tags": [ + "Pipeline" + ], + "operationId": "listMyPipelines", + "responses": { + "200": { + "description": "A sequence of pipelines.", + "links": { + "NextPipelinePage": { + "operationId": "listMyPipelines", + "parameters": { + "project-slug": "$request.path.project-slug", + "page-token": "$response.body#/next_page_token" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of error." + }, + "message": { + "type": "string", + "description": "A human-readable error message." + } + }, + "required": [ + "type", + "message" + ], + "description": "An error with a type and message." + }, + "description": "A sequence of errors that have occurred within the pipeline." + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline.", + "example": 25 + }, + "trigger_parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + } + }, + "state": { + "type": "string", + "description": "The current state of the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "trigger": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of trigger." + }, + "received_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was received." + }, + "actor": { + "type": "object", + "properties": { + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + } + }, + "required": [ + "login", + "avatar_url" + ], + "description": "The user who triggered the Pipeline." + } + }, + "required": [ + "type", + "received_at", + "actor" + ], + "description": "A summary of the trigger." + }, + "vcs": { + "type": "object", + "properties": { + "provider_name": { + "type": "string", + "description": "Name of the VCS provider (e.g. GitHub, Bitbucket).", + "example": "GitHub" + }, + "target_repository_url": { + "type": "string", + "description": "URL for the repository the trigger targets (i.e. the repository where the PR will be merged). For fork-PR pipelines, this is the URL to the parent repo. For other pipelines, the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "branch": { + "type": "string", + "description": "The branch where the pipeline ran. The HEAD commit on this branch was used for the pipeline. Note that `branch` and `tag` are mutually exclusive. To trigger a pipeline for a PR by number use `pull//head` for the PR ref or `pull//merge` for the merge ref (GitHub only).", + "example": "feature/design-new-api" + }, + "review_id": { + "type": "string", + "description": "The code review id.", + "example": "123" + }, + "review_url": { + "type": "string", + "description": "The code review URL.", + "example": "https://github.com/CircleCI-Public/api-preview-docs/pull/123" + }, + "revision": { + "type": "string", + "x-nullable": true, + "description": "The code revision the pipeline ran.", + "example": "f454a02b5d10fcccfd7d9dd7608a76d6493a98b4" + }, + "tag": { + "type": "string", + "description": "The tag used by the pipeline. The commit that this tag points to was used for the pipeline. Note that `branch` and `tag` are mutually exclusive.", + "example": "v3.1.4159" + }, + "commit": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "x-nullable": true, + "description": "The subject of the commit message." + }, + "body": { + "type": "string", + "x-nullable": true, + "description": "The body of the commit message." + } + }, + "required": [ + "subject", + "body" + ], + "description": "The latest commit in the pipeline." + }, + "origin_repository_url": { + "type": "string", + "description": "URL for the repository where the trigger originated. For fork-PR pipelines, this is the URL to the fork. For other pipelines the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + } + }, + "required": [ + "provider_name", + "origin_repository_url", + "target_repository_url", + "revision" + ], + "description": "VCS information for the pipeline." + } + }, + "required": [ + "id", + "number", + "project_slug", + "created_at", + "errors", + "state", + "trigger" + ], + "description": "A pipeline response.", + "title": "Pipeline" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "List of pipelines", + "title": "PipelineListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/mine?page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/mine?page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/mine?page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/mine?page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/mine?page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/pipeline/{pipeline-number}": { + "get": { + "summary": "Get a pipeline by pipeline number", + "description": "Returns a pipeline by the pipeline number.", + "tags": [ + "Pipeline" + ], + "operationId": "getPipelineByNumber", + "responses": { + "200": { + "description": "A pipeline object.", + "links": { + "ProjectFromPipeline": { + "operationId": "getProjectBySlug", + "parameters": { + "project_slug": "$response.body#/project_slug" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of error." + }, + "message": { + "type": "string", + "description": "A human-readable error message." + } + }, + "required": [ + "type", + "message" + ], + "description": "An error with a type and message." + }, + "description": "A sequence of errors that have occurred within the pipeline." + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline.", + "example": 25 + }, + "trigger_parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int64" + }, + { + "type": "boolean" + }, + { + "type": "object" + } + ] + } + }, + "state": { + "type": "string", + "description": "The current state of the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "trigger": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of trigger." + }, + "received_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was received." + }, + "actor": { + "type": "object", + "properties": { + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + } + }, + "required": [ + "login", + "avatar_url" + ], + "description": "The user who triggered the Pipeline." + } + }, + "required": [ + "type", + "received_at", + "actor" + ], + "description": "A summary of the trigger." + }, + "vcs": { + "type": "object", + "properties": { + "provider_name": { + "type": "string", + "description": "Name of the VCS provider (e.g. GitHub, Bitbucket).", + "example": "GitHub" + }, + "target_repository_url": { + "type": "string", + "description": "URL for the repository the trigger targets (i.e. the repository where the PR will be merged). For fork-PR pipelines, this is the URL to the parent repo. For other pipelines, the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + }, + "branch": { + "type": "string", + "description": "The branch where the pipeline ran. The HEAD commit on this branch was used for the pipeline. Note that `branch` and `tag` are mutually exclusive. To trigger a pipeline for a PR by number use `pull//head` for the PR ref or `pull//merge` for the merge ref (GitHub only).", + "example": "feature/design-new-api" + }, + "review_id": { + "type": "string", + "description": "The code review id.", + "example": "123" + }, + "review_url": { + "type": "string", + "description": "The code review URL.", + "example": "https://github.com/CircleCI-Public/api-preview-docs/pull/123" + }, + "revision": { + "type": "string", + "x-nullable": true, + "description": "The code revision the pipeline ran.", + "example": "f454a02b5d10fcccfd7d9dd7608a76d6493a98b4" + }, + "tag": { + "type": "string", + "description": "The tag used by the pipeline. The commit that this tag points to was used for the pipeline. Note that `branch` and `tag` are mutually exclusive.", + "example": "v3.1.4159" + }, + "commit": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "x-nullable": true, + "description": "The subject of the commit message." + }, + "body": { + "type": "string", + "x-nullable": true, + "description": "The body of the commit message." + } + }, + "required": [ + "subject", + "body" + ], + "description": "The latest commit in the pipeline." + }, + "origin_repository_url": { + "type": "string", + "description": "URL for the repository where the trigger originated. For fork-PR pipelines, this is the URL to the fork. For other pipelines the `origin_` and `target_repository_url`s will be the same.", + "example": "https://github.com/CircleCI-Public/api-preview-docs" + } + }, + "required": [ + "provider_name", + "origin_repository_url", + "target_repository_url", + "revision" + ], + "description": "VCS information for the pipeline." + } + }, + "required": [ + "id", + "number", + "project_slug", + "created_at", + "errors", + "state", + "trigger" + ], + "description": "A pipeline response.", + "title": "Pipeline" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "path", + "name": "pipeline-number", + "description": "The number of the pipeline.", + "schema": {}, + "required": true, + "example": "123" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/123 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/123';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/123\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/123\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/123\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/schedule": { + "post": { + "summary": "Create a schedule", + "description": "Not yet available to projects that use GitLab or GitHub App. Creates a schedule and returns the created schedule.", + "tags": [ + "Schedule" + ], + "operationId": "createSchedule", + "responses": { + "201": { + "description": "A schedule object.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the schedule." + }, + "timetable": { + "anyOf": [ + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-week" + ] + }, + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-month" + ] + } + ], + "description": "Timetable that specifies when a schedule triggers." + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "name": { + "type": "string", + "description": "Name of the schedule." + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "project-slug": { + "type": "string", + "description": "The project-slug for the schedule", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "Pipeline parameters represented as key-value pairs. Must contain branch or tag.", + "example": { + "deploy_prod": true, + "branch": "feature/design-new-api" + } + }, + "actor": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "name": { + "type": "string", + "description": "The name of the user." + } + }, + "required": [ + "avatar_url", + "id", + "login", + "name" + ], + "title": "User", + "description": "The attribution actor who will run the scheduled pipeline." + }, + "description": { + "type": "string", + "x-nullable": true, + "description": "Description of the schedule." + } + }, + "required": [ + "id", + "name", + "timetable", + "description", + "project-slug", + "actor", + "created-at", + "updated-at", + "parameters" + ], + "description": "A schedule response", + "title": "Schedule" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the schedule." + }, + "timetable": { + "anyOf": [ + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-week" + ] + }, + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-month" + ] + } + ], + "description": "Timetable that specifies when a schedule triggers." + }, + "attribution-actor": { + "type": "string", + "description": "The attribution-actor of the scheduled pipeline.", + "example": "current" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "Pipeline parameters represented as key-value pairs. Must contain branch or tag.", + "example": { + "deploy_prod": true, + "branch": "feature/design-new-api" + } + }, + "description": { + "type": "string", + "x-nullable": true, + "description": "Description of the schedule." + } + }, + "required": [ + "name", + "timetable", + "attribution-actor", + "parameters" + ], + "description": "The parameters for a create schedule request", + "title": "CreateScheduleParameters" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"example-string\\\",\n \\\"timetable\\\": null,\n \\\"attribution-actor\\\": \\\"current\\\",\n \\\"parameters\\\": {\n \\\"deploy_prod\\\": true,\n \\\"branch\\\": \\\"feature/design-new-api\\\"\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"example-string\",\"timetable\":null,\"attribution-actor\":\"current\",\"parameters\":{\"deploy_prod\":true,\"branch\":\"feature/design-new-api\"}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"timetable\\\": null,\\n \\\"attribution-actor\\\": \\\"current\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true,\\n \\\"branch\\\": \\\"feature/design-new-api\\\"\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"timetable\\\": null,\\n \\\"attribution-actor\\\": \\\"current\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true,\\n \\\"branch\\\": \\\"feature/design-new-api\\\"\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"timetable\\\": null,\\n \\\"attribution-actor\\\": \\\"current\\\",\\n \\\"parameters\\\": {\\n \\\"deploy_prod\\\": true,\\n \\\"branch\\\": \\\"feature/design-new-api\\\"\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "Get all schedules", + "description": "Returns all schedules for this project.", + "tags": [ + "Schedule" + ], + "operationId": "listSchedulesForProject", + "responses": { + "200": { + "description": "A sequence of schedules.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the schedule." + }, + "timetable": { + "anyOf": [ + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-week" + ] + }, + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-month" + ] + } + ], + "description": "Timetable that specifies when a schedule triggers." + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "name": { + "type": "string", + "description": "Name of the schedule." + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "project-slug": { + "type": "string", + "description": "The project-slug for the schedule", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "Pipeline parameters represented as key-value pairs. Must contain branch or tag.", + "example": { + "deploy_prod": true, + "branch": "feature/design-new-api" + } + }, + "actor": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "name": { + "type": "string", + "description": "The name of the user." + } + }, + "required": [ + "avatar_url", + "id", + "login", + "name" + ], + "title": "User", + "description": "The attribution actor who will run the scheduled pipeline." + }, + "description": { + "type": "string", + "x-nullable": true, + "description": "Description of the schedule." + } + }, + "required": [ + "id", + "name", + "timetable", + "description", + "project-slug", + "actor", + "created-at", + "updated-at", + "parameters" + ], + "description": "A schedule response", + "title": "Schedule" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "A sequence of schedules" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + }, + { + "in": "query", + "name": "page-token", + "description": "A token to retrieve the next page of results.", + "schema": { + "type": "string" + }, + "required": false, + "allowEmptyValue": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule?page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule?page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule?page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule?page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/schedule?page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/{job-number}/artifacts": { + "get": { + "summary": "Get a job's artifacts", + "description": "Returns a job's artifacts.", + "tags": [ + "Job" + ], + "operationId": "getJobArtifacts", + "responses": { + "200": { + "description": "A paginated list of the job's artifacts.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "The artifact path." + }, + "node_index": { + "type": "integer", + "format": "int64", + "minimum": 0, + "description": "The index of the node that stored the artifact." + }, + "url": { + "type": "string", + "description": "The URL to download the artifact contents." + } + }, + "required": [ + "path", + "node_index", + "url" + ], + "description": "An artifact", + "title": "Artifact" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "title": "ArtifactListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "job-number", + "description": "The number of the job.", + "schema": {}, + "required": true, + "example": "123" + }, + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/artifacts \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/artifacts';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/artifacts\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/artifacts\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/artifacts\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{project-slug}/{job-number}/tests": { + "get": { + "summary": "Get test metadata", + "description": "Get test metadata for a build. In the rare case where there is more than 250MB of test data on the job, no results will be returned.", + "tags": [ + "Job" + ], + "operationId": "getTests", + "responses": { + "200": { + "description": "A paginated list of test results.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string", + "x-nullable": true, + "description": "The failure message associated with the test.", + "example": "" + }, + "source": { + "type": "string", + "description": "The program that generated the test results", + "example": "" + }, + "run_time": { + "type": "number", + "format": "double", + "description": "The time it took to run the test in seconds", + "example": "" + }, + "file": { + "type": "string", + "description": "The file in which the test is defined.", + "example": "" + }, + "result": { + "type": "string", + "description": "Indication of whether the test succeeded.", + "example": "" + }, + "name": { + "type": "string", + "description": "The name of the test.", + "example": "" + }, + "classname": { + "type": "string", + "description": "The programmatic location of the test.", + "example": "" + } + }, + "required": [ + "message", + "source", + "run_time", + "file", + "result", + "name", + "classname" + ] + }, + "title": "TestsResponse" + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "title": "TestsResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "job-number", + "description": "The number of the job.", + "schema": {}, + "required": true, + "example": "123" + }, + { + "in": "path", + "name": "project-slug", + "description": "Project slug in the form `vcs-slug/org-name/repo-name`. The `/` characters may be URL-escaped. For projects that use GitLab or GitHub App, use `circleci` as the `vcs-slug`, replace `org-name` with the organization ID (found in Organization Settings), and replace `repo-name` with the project ID (found in Project Settings).", + "schema": { + "type": "string" + }, + "required": true, + "example": "gh/CircleCI-Public/api-preview-docs", + "allowReserved": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/tests \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/tests';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/tests\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/tests\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/123/tests\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/schedule/{schedule-id}": { + "patch": { + "summary": "Update a schedule", + "description": "Not yet available to projects that use GitLab or GitHub App. Updates a schedule and returns the updated schedule.", + "tags": [ + "Schedule" + ], + "operationId": "updateSchedule", + "responses": { + "200": { + "description": "A schedule object.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the schedule." + }, + "timetable": { + "anyOf": [ + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-week" + ] + }, + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-month" + ] + } + ], + "description": "Timetable that specifies when a schedule triggers." + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "name": { + "type": "string", + "description": "Name of the schedule." + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "project-slug": { + "type": "string", + "description": "The project-slug for the schedule", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "Pipeline parameters represented as key-value pairs. Must contain branch or tag.", + "example": { + "deploy_prod": true, + "branch": "feature/design-new-api" + } + }, + "actor": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "name": { + "type": "string", + "description": "The name of the user." + } + }, + "required": [ + "avatar_url", + "id", + "login", + "name" + ], + "title": "User", + "description": "The attribution actor who will run the scheduled pipeline." + }, + "description": { + "type": "string", + "x-nullable": true, + "description": "Description of the schedule." + } + }, + "required": [ + "id", + "name", + "timetable", + "description", + "project-slug", + "actor", + "created-at", + "updated-at", + "parameters" + ], + "description": "A schedule response", + "title": "Schedule" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "schedule-id", + "description": "The unique ID of the schedule.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "description": { + "type": "string", + "x-nullable": true, + "description": "Description of the schedule." + }, + "name": { + "type": "string", + "description": "Name of the schedule." + }, + "timetable": { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "description": "Timetable that specifies when a schedule triggers." + }, + "attribution-actor": { + "type": "string", + "description": "The attribution-actor of the scheduled pipeline.", + "example": "current" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "Pipeline parameters represented as key-value pairs. Must contain branch or tag.", + "example": { + "deploy_prod": true, + "branch": "feature/design-new-api" + } + } + }, + "description": "The parameters for an update schedule request", + "title": "UpdateScheduleParameters" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"description\\\": \\\"example-string\\\",\n \\\"name\\\": \\\"example-string\\\",\n \\\"timetable\\\": {\n \\\"per-hour\\\": 123,\n \\\"hours-of-day\\\": [\n 123\n ],\n \\\"days-of-week\\\": [\n \\\"TUE\\\"\n ]\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"description\":\"example-string\",\"name\":\"example-string\",\"timetable\":{\"per-hour\":123,\"hours-of-day\":[123],\"days-of-week\":[\"TUE\"]}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"description\\\": \\\"example-string\\\",\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"timetable\\\": {\\n \\\"per-hour\\\": 123,\\n \\\"hours-of-day\\\": [\\n 123\\n ],\\n \\\"days-of-week\\\": [\\n \\\"TUE\\\"\\n ]\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"description\\\": \\\"example-string\\\",\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"timetable\\\": {\\n \\\"per-hour\\\": 123,\\n \\\"hours-of-day\\\": [\\n 123\\n ],\\n \\\"days-of-week\\\": [\\n \\\"TUE\\\"\\n ]\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"description\\\": \\\"example-string\\\",\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"timetable\\\": {\\n \\\"per-hour\\\": 123,\\n \\\"hours-of-day\\\": [\\n 123\\n ],\\n \\\"days-of-week\\\": [\\n \\\"TUE\\\"\\n ]\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Delete a schedule", + "description": "Not yet available to projects that use GitLab or GitHub App. Deletes the schedule by id.", + "tags": [ + "Schedule" + ], + "operationId": "deleteScheduleById", + "responses": { + "200": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "schedule-id", + "description": "The unique ID of the schedule.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "Get a schedule", + "description": "Get a schedule by id.", + "tags": [ + "Schedule" + ], + "operationId": "getScheduleById", + "responses": { + "200": { + "description": "A schedule object.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the schedule." + }, + "timetable": { + "anyOf": [ + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-week" + ] + }, + { + "type": "object", + "properties": { + "per-hour": { + "type": "integer", + "format": "integer", + "description": "Number of times a schedule triggers per hour, value must be between 1 and 60" + }, + "hours-of-day": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Hour in a day in UTC, value must be between 0 and 24" + }, + "description": "Hours in a day in which the schedule triggers." + }, + "days-of-month": { + "type": "array", + "items": { + "type": "integer", + "format": "integer", + "description": "Day in a month, between 1 and 31." + }, + "description": "Days in a month in which the schedule triggers. This is mutually exclusive with days in a week." + }, + "days-of-week": { + "type": "array", + "items": { + "type": "string", + "description": "Day in a week, in three letters format" + }, + "description": "Days in a week in which the schedule triggers." + }, + "months": { + "type": "array", + "items": { + "type": "string", + "description": "Month, in three letters format." + }, + "description": "Months in which the schedule triggers." + } + }, + "required": [ + "per-hour", + "hours-of-day", + "days-of-month" + ] + } + ], + "description": "Timetable that specifies when a schedule triggers." + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was last updated." + }, + "name": { + "type": "string", + "description": "Name of the schedule." + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline was created." + }, + "project-slug": { + "type": "string", + "description": "The project-slug for the schedule", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "parameters": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + }, + { + "type": "boolean" + } + ] + }, + "description": "Pipeline parameters represented as key-value pairs. Must contain branch or tag.", + "example": { + "deploy_prod": true, + "branch": "feature/design-new-api" + } + }, + "actor": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "name": { + "type": "string", + "description": "The name of the user." + } + }, + "required": [ + "avatar_url", + "id", + "login", + "name" + ], + "title": "User", + "description": "The attribution actor who will run the scheduled pipeline." + }, + "description": { + "type": "string", + "x-nullable": true, + "description": "Description of the schedule." + } + }, + "required": [ + "id", + "name", + "timetable", + "description", + "project-slug", + "actor", + "created-at", + "updated-at", + "parameters" + ], + "description": "A schedule response", + "title": "Schedule" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "schedule-id", + "description": "The unique ID of the schedule.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/schedule/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/user/{id}": { + "get": { + "summary": "User Information", + "description": "Provides information about the user with the given ID.", + "tags": [ + "User" + ], + "operationId": "getUser", + "responses": { + "200": { + "description": "User login information.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "avatar_url": { + "type": "string", + "x-nullable": true, + "description": "URL to the user's avatar on the VCS" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "login": { + "type": "string", + "description": "The login information for the user on the VCS.", + "title": "Login" + }, + "name": { + "type": "string", + "description": "The name of the user." + } + }, + "required": [ + "avatar_url", + "id", + "login", + "name" + ], + "title": "User" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The unique ID of the user.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/user/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/user/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/user/497f6eca-6276-4993-bfeb-53cbbbba6f08\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/user/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/user/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/webhook": { + "post": { + "summary": "Create an outbound webhook", + "description": "Creates an outbound webhook.", + "tags": [ + "Webhook" + ], + "operationId": "createWebhook", + "responses": { + "201": { + "description": "A webhook", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL to deliver the webhook to. Note: protocol must be included as well (only https is supported)" + }, + "verify-tls": { + "type": "boolean", + "description": "Whether to enforce TLS certificate verification when delivering the webhook" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the webhook" + }, + "signing-secret": { + "type": "string", + "description": "Masked value of the secret used to build an HMAC hash of the payload and passed as a header in the webhook request" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was last updated.", + "example": "2015-09-21T17:29:21.042Z" + }, + "name": { + "type": "string", + "description": "Name of the webhook" + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was created.", + "example": "2015-09-21T17:29:21.042Z" + }, + "scope": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the scope being used (at the moment, only project ID is supported)" + }, + "type": { + "type": "string", + "description": "Type of the scope being used" + } + }, + "required": [ + "id", + "type" + ], + "description": "The scope in which the relevant events that will trigger webhooks" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Events that will trigger the webhook" + } + }, + "required": [ + "id", + "scope", + "name", + "events", + "url", + "verify-tls", + "signing-secret", + "created-at", + "updated-at" + ], + "title": "Webhook" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the webhook" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Events that will trigger the webhook" + }, + "url": { + "type": "string", + "description": "URL to deliver the webhook to. Note: protocol must be included as well (only https is supported)" + }, + "verify-tls": { + "type": "boolean", + "description": "Whether to enforce TLS certificate verification when delivering the webhook" + }, + "signing-secret": { + "type": "string", + "description": "Secret used to build an HMAC hash of the payload and passed as a header in the webhook request" + }, + "scope": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the scope being used (at the moment, only project ID is supported)" + }, + "type": { + "type": "string", + "description": "Type of the scope being used" + } + }, + "required": [ + "id", + "type" + ], + "description": "The scope in which the relevant events that will trigger webhooks" + } + }, + "required": [ + "name", + "events", + "url", + "verify-tls", + "signing-secret", + "scope" + ], + "description": "The parameters for a create webhook request" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/webhook \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"example-string\\\",\n \\\"events\\\": [\n \\\"workflow-completed\\\"\n ],\n \\\"url\\\": \\\"example-string\\\",\n \\\"verify-tls\\\": true,\n \\\"signing-secret\\\": \\\"example-string\\\",\n \\\"scope\\\": {\n \\\"id\\\": \\\"example-string\\\",\n \\\"type\\\": \\\"project\\\"\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/webhook';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"example-string\",\"events\":[\"workflow-completed\"],\"url\":\"example-string\",\"verify-tls\":true,\"signing-secret\":\"example-string\",\"scope\":{\"id\":\"example-string\",\"type\":\"project\"}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"events\\\": [\\n \\\"workflow-completed\\\"\\n ],\\n \\\"url\\\": \\\"example-string\\\",\\n \\\"verify-tls\\\": true,\\n \\\"signing-secret\\\": \\\"example-string\\\",\\n \\\"scope\\\": {\\n \\\"id\\\": \\\"example-string\\\",\\n \\\"type\\\": \\\"project\\\"\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/webhook\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/webhook\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"events\\\": [\\n \\\"workflow-completed\\\"\\n ],\\n \\\"url\\\": \\\"example-string\\\",\\n \\\"verify-tls\\\": true,\\n \\\"signing-secret\\\": \\\"example-string\\\",\\n \\\"scope\\\": {\\n \\\"id\\\": \\\"example-string\\\",\\n \\\"type\\\": \\\"project\\\"\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/webhook\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"events\\\": [\\n \\\"workflow-completed\\\"\\n ],\\n \\\"url\\\": \\\"example-string\\\",\\n \\\"verify-tls\\\": true,\\n \\\"signing-secret\\\": \\\"example-string\\\",\\n \\\"scope\\\": {\\n \\\"id\\\": \\\"example-string\\\",\\n \\\"type\\\": \\\"project\\\"\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "List webhooks", + "description": "Get a list of outbound webhooks that match the given scope-type and scope-id", + "tags": [ + "Webhook" + ], + "operationId": "getWebhooks", + "responses": { + "200": { + "description": "A list of webhooks", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL to deliver the webhook to. Note: protocol must be included as well (only https is supported)" + }, + "verify-tls": { + "type": "boolean", + "description": "Whether to enforce TLS certificate verification when delivering the webhook" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the webhook" + }, + "signing-secret": { + "type": "string", + "description": "Masked value of the secret used to build an HMAC hash of the payload and passed as a header in the webhook request" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was last updated.", + "example": "2015-09-21T17:29:21.042Z" + }, + "name": { + "type": "string", + "description": "Name of the webhook" + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was created.", + "example": "2015-09-21T17:29:21.042Z" + }, + "scope": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the scope being used (at the moment, only project ID is supported)" + }, + "type": { + "type": "string", + "description": "Type of the scope being used" + } + }, + "required": [ + "id", + "type" + ], + "description": "The scope in which the relevant events that will trigger webhooks" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Events that will trigger the webhook" + } + }, + "required": [ + "id", + "scope", + "name", + "events", + "url", + "verify-tls", + "signing-secret", + "created-at", + "updated-at" + ], + "title": "Webhook" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "description": "A list of webhooks" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "query", + "name": "scope-id", + "description": "ID of the scope being used (at the moment, only project ID is supported)", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + }, + { + "in": "query", + "name": "scope-type", + "description": "Type of the scope being used", + "schema": { + "type": "string" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/webhook?scope-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&scope-type=project\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/webhook?scope-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&scope-type=project';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/webhook?scope-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&scope-type=project\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/webhook?scope-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&scope-type=project\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/webhook?scope-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&scope-type=project\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/webhook/{webhook-id}": { + "put": { + "summary": "Update an outbound webhook", + "description": "Updates an outbound webhook.", + "tags": [ + "Webhook" + ], + "operationId": "updateWebhook", + "responses": { + "200": { + "description": "A webhook", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL to deliver the webhook to. Note: protocol must be included as well (only https is supported)" + }, + "verify-tls": { + "type": "boolean", + "description": "Whether to enforce TLS certificate verification when delivering the webhook" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the webhook" + }, + "signing-secret": { + "type": "string", + "description": "Masked value of the secret used to build an HMAC hash of the payload and passed as a header in the webhook request" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was last updated.", + "example": "2015-09-21T17:29:21.042Z" + }, + "name": { + "type": "string", + "description": "Name of the webhook" + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was created.", + "example": "2015-09-21T17:29:21.042Z" + }, + "scope": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the scope being used (at the moment, only project ID is supported)" + }, + "type": { + "type": "string", + "description": "Type of the scope being used" + } + }, + "required": [ + "id", + "type" + ], + "description": "The scope in which the relevant events that will trigger webhooks" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Events that will trigger the webhook" + } + }, + "required": [ + "id", + "scope", + "name", + "events", + "url", + "verify-tls", + "signing-secret", + "created-at", + "updated-at" + ], + "title": "Webhook" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "webhook-id", + "description": "ID of the webhook (UUID)", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the webhook" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Events that will trigger the webhook" + }, + "url": { + "type": "string", + "description": "URL to deliver the webhook to. Note: protocol must be included as well (only https is supported)" + }, + "signing-secret": { + "type": "string", + "description": "Secret used to build an HMAC hash of the payload and passed as a header in the webhook request" + }, + "verify-tls": { + "type": "boolean", + "description": "Whether to enforce TLS certificate verification when delivering the webhook" + } + }, + "description": "The parameters for an update webhook request" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PUT \\\n --url https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"example-string\\\",\n \\\"events\\\": [\n \\\"workflow-completed\\\"\n ],\n \\\"url\\\": \\\"example-string\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {\n method: 'PUT',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"example-string\",\"events\":[\"workflow-completed\"],\"url\":\"example-string\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"events\\\": [\\n \\\"workflow-completed\\\"\\n ],\\n \\\"url\\\": \\\"example-string\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PUT\", \"/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"events\\\": [\\n \\\"workflow-completed\\\"\\n ],\\n \\\"url\\\": \\\"example-string\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"PUT\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Put.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"events\\\": [\\n \\\"workflow-completed\\\"\\n ],\\n \\\"url\\\": \\\"example-string\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Delete an outbound webhook", + "description": "Deletes an outbound webhook", + "tags": [ + "Webhook" + ], + "operationId": "deleteWebhook", + "responses": { + "200": { + "description": "A confirmation message", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "webhook-id", + "description": "ID of the webhook (UUID)", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "Get a webhook", + "description": "Get an outbound webhook by id.", + "tags": [ + "Webhook" + ], + "operationId": "getWebhookById", + "responses": { + "200": { + "description": "A webhook", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL to deliver the webhook to. Note: protocol must be included as well (only https is supported)" + }, + "verify-tls": { + "type": "boolean", + "description": "Whether to enforce TLS certificate verification when delivering the webhook" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the webhook" + }, + "signing-secret": { + "type": "string", + "description": "Masked value of the secret used to build an HMAC hash of the payload and passed as a header in the webhook request" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was last updated.", + "example": "2015-09-21T17:29:21.042Z" + }, + "name": { + "type": "string", + "description": "Name of the webhook" + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date and time the webhook was created.", + "example": "2015-09-21T17:29:21.042Z" + }, + "scope": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the scope being used (at the moment, only project ID is supported)" + }, + "type": { + "type": "string", + "description": "Type of the scope being used" + } + }, + "required": [ + "id", + "type" + ], + "description": "The scope in which the relevant events that will trigger webhooks" + }, + "events": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Events that will trigger the webhook" + } + }, + "required": [ + "id", + "scope", + "name", + "events", + "url", + "verify-tls", + "signing-secret", + "created-at", + "updated-at" + ], + "title": "Webhook" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "webhook-id", + "description": "ID of the webhook (UUID)", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/webhook/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/workflow/{id}": { + "get": { + "summary": "Get a workflow", + "description": "Returns summary fields of a workflow by ID.", + "tags": [ + "Workflow" + ], + "operationId": "getWorkflowById", + "responses": { + "200": { + "description": "A workflow object.", + "links": { + "ProjectFromGetWorkflow": { + "operationId": "getProjectBySlug", + "parameters": { + "project_slug": "$response.body#/project_slug" + } + }, + "WorkflowJobs": { + "operationId": "listWorkflowJobs", + "parameters": { + "id": "$response.body#/id" + } + }, + "CancelWorkflow": { + "operationId": "cancelWorkflow", + "parameters": { + "id": "$response.body#/id" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "pipeline_id": { + "type": "string", + "format": "uuid", + "description": "The ID of the pipeline this workflow belongs to.", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + }, + "canceled_by": { + "type": "string", + "format": "uuid" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the workflow." + }, + "auto_rerun_number": { + "type": "integer", + "format": "int64", + "minimum": 1, + "description": "Present if this workflow was auto-rerun from a previous workflow. The Nth auto-rerun workflow will have auto_rerun_number N", + "example": 1 + }, + "name": { + "type": "string", + "description": "The name of the workflow.", + "example": "build-and-test" + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the pipeline this workflow belongs to.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "errored_by": { + "type": "string", + "format": "uuid" + }, + "tag": { + "type": "string", + "x-nullable": true, + "description": "Tag used for the workflow", + "example": "setup" + }, + "status": { + "type": "string", + "description": "The current status of the workflow." + }, + "started_by": { + "type": "string", + "format": "uuid" + }, + "max_auto_reruns": { + "type": "integer", + "format": "int64", + "minimum": 1, + "description": "The maximum number of auto reruns specified for the workflow.", + "example": 5 + }, + "pipeline_number": { + "type": "integer", + "format": "int64", + "description": "The number of the pipeline this workflow belongs to.", + "example": 25 + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the workflow was created." + }, + "stopped_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "The date and time the workflow stopped." + } + }, + "required": [ + "id", + "name", + "status", + "created_at", + "stopped_at", + "pipeline_id", + "pipeline_number", + "project_slug", + "started_by" + ], + "description": "A workflow", + "title": "Workflow" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The unique ID of the workflow.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/workflow/{id}/approve/{approval_request_id}": { + "post": { + "summary": "Approve a job", + "description": "Approves a pending approval job in a workflow.", + "tags": [ + "Workflow" + ], + "operationId": "approvePendingApprovalJobById", + "responses": { + "202": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "approval_request_id", + "description": "The ID of the job being approved.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true + }, + { + "in": "path", + "name": "id", + "description": "The unique ID of the workflow.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/approve/497f6eca-6276-4993-bfeb-53cbbbba6f08 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/approve/497f6eca-6276-4993-bfeb-53cbbbba6f08';\n const options = {method: 'POST', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"POST\", \"/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/approve/497f6eca-6276-4993-bfeb-53cbbbba6f08\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/approve/497f6eca-6276-4993-bfeb-53cbbbba6f08\"\n\n\treq, _ := http.NewRequest(\"POST\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/approve/497f6eca-6276-4993-bfeb-53cbbbba6f08\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/workflow/{id}/cancel": { + "post": { + "summary": "Cancel a workflow", + "description": "Cancels a running workflow.", + "tags": [ + "Workflow" + ], + "operationId": "cancelWorkflow", + "responses": { + "202": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The unique ID of the workflow.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/cancel \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/cancel';\n const options = {method: 'POST', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"POST\", \"/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/cancel\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/cancel\"\n\n\treq, _ := http.NewRequest(\"POST\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/cancel\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/workflow/{id}/job": { + "get": { + "summary": "Get a workflow's jobs", + "description": "Returns a sequence of jobs for a workflow.", + "tags": [ + "Workflow" + ], + "operationId": "listWorkflowJobs", + "responses": { + "200": { + "description": "A paginated sequence of jobs.", + "links": { + "NextWorkflowJobPage": { + "operationId": "listWorkflowJobs", + "parameters": { + "id": "$request.path.id", + "page-token": "$response.body#/next_page_token" + } + } + }, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "canceled_by": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "dependencies": { + "type": "array", + "items": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the job." + }, + "description": "A sequence of the unique job IDs for the jobs that this job depends upon in the workflow." + }, + "job_number": { + "type": "integer", + "format": "int64", + "description": "The number of the job.", + "example": 1 + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the job." + }, + "started_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the job started." + }, + "name": { + "type": "string", + "description": "The name of the job." + }, + "approved_by": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the user." + }, + "project_slug": { + "type": "string", + "description": "The project-slug for the job.", + "example": "gh/CircleCI-Public/api-preview-docs" + }, + "status": { + "type": "string", + "description": "The current status of the job." + }, + "type": { + "type": "string", + "description": "The type of job." + }, + "requires": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A sequence of statuses that the job must have one of to satisfy a dependency." + }, + "description": "A sequence of the unique jobs and required statuses that this job depends upon in the workflow.", + "example": { + "d212e286-9962-4ed7-92e2-8699622ed720": [ + "success" + ], + "74be7583-44de-42a6-be75-8344de52a6f2": [ + "failed", + "canceled" + ], + "a3349b77-90f7-4a39-b49b-7790f7da3943": [ + "success", + "failed", + "canceled" + ] + } + }, + "stopped_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "The time when the job stopped." + }, + "approval_request_id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the job." + } + }, + "required": [ + "id", + "name", + "started_at", + "dependencies", + "project_slug", + "status", + "type" + ], + "description": "Job", + "title": "Job" + } + }, + "next_page_token": { + "type": "string", + "x-nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ], + "title": "WorkflowJobListResponse" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The unique ID of the workflow.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/job \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/job';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/job\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/job\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/job\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/workflow/{id}/rerun": { + "post": { + "summary": "Rerun a workflow", + "description": "Reruns a workflow.", + "tags": [ + "Workflow" + ], + "operationId": "rerunWorkflow", + "responses": { + "202": { + "description": "A confirmation message.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "workflow_id": { + "type": "string", + "format": "uuid", + "description": "The ID of the newly-created workflow.", + "example": "0e53027b-521a-4c40-9042-47e72b3c63a3" + } + }, + "required": [ + "workflow_id" + ], + "description": "A response to rerunning a workflow" + } + } + } + }, + "default": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + }, + "description": "Error response." + } + }, + "parameters": [ + { + "in": "path", + "name": "id", + "description": "The unique ID of the workflow.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "enable_ssh": { + "type": "boolean", + "description": "Whether to enable SSH access for the triggering user on the newly-rerun job. Requires the jobs parameter to be used and so is mutually exclusive with the from_failed parameter.", + "example": false + }, + "from_failed": { + "type": "boolean", + "description": "Whether to rerun the workflow from the failed job. Mutually exclusive with the jobs parameter.", + "example": false + }, + "jobs": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "A list of job IDs to rerun.", + "example": [ + "c65b68ef-e73b-4bf2-be9a-7a322a9df150", + "5e957edd-5e8c-4985-9178-5d0d69561822" + ] + }, + "sparse_tree": { + "type": "boolean", + "description": "Completes rerun using sparse trees logic, an optimization for workflows that have disconnected subgraphs. Requires jobs parameter and so is mutually exclusive with the from_failed parameter.", + "example": false + } + }, + "x-nullable": true, + "description": "The information you can supply when rerunning a workflow.", + "title": "RerunWorkflowParameters" + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/rerun \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"enable_ssh\\\": false,\n \\\"from_failed\\\": false,\n \\\"jobs\\\": [\n \\\"c65b68ef-e73b-4bf2-be9a-7a322a9df150\\\",\n \\\"5e957edd-5e8c-4985-9178-5d0d69561822\\\"\n ]\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/rerun';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"enable_ssh\":false,\"from_failed\":false,\"jobs\":[\"c65b68ef-e73b-4bf2-be9a-7a322a9df150\",\"5e957edd-5e8c-4985-9178-5d0d69561822\"]}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"enable_ssh\\\": false,\\n \\\"from_failed\\\": false,\\n \\\"jobs\\\": [\\n \\\"c65b68ef-e73b-4bf2-be9a-7a322a9df150\\\",\\n \\\"5e957edd-5e8c-4985-9178-5d0d69561822\\\"\\n ]\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/rerun\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/rerun\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"enable_ssh\\\": false,\\n \\\"from_failed\\\": false,\\n \\\"jobs\\\": [\\n \\\"c65b68ef-e73b-4bf2-be9a-7a322a9df150\\\",\\n \\\"5e957edd-5e8c-4985-9178-5d0d69561822\\\"\\n ]\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/workflow/5034460f-c7c4-4c43-9457-de07e2029e7b/rerun\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"enable_ssh\\\": false,\\n \\\"from_failed\\\": false,\\n \\\"jobs\\\": [\\n \\\"c65b68ef-e73b-4bf2-be9a-7a322a9df150\\\",\\n \\\"5e957edd-5e8c-4985-9178-5d0d69561822\\\"\\n ]\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/org/{orgID}/oidc-custom-claims": { + "delete": { + "description": "Deletes org-level custom claims of OIDC identity tokens", + "operationId": "DeleteOrgClaims", + "parameters": [ + { + "in": "path", + "name": "orgID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "comma separated list of claims to delete. Valid values are \"audience\" and \"ttl\".", + "in": "query", + "name": "claims", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + } + } + }, + "description": "Claims successfully deleted." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "internal server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Delete org-level claims", + "tags": [ + "OIDC Token Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url \"https://circleci.com/api/v2/org/example-value/oidc-custom-claims?claims=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/org/example-value/oidc-custom-claims?claims=example-value';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/org/example-value/oidc-custom-claims?claims=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/org/example-value/oidc-custom-claims?claims=example-value\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/org/example-value/oidc-custom-claims?claims=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "description": "Fetches org-level custom claims of OIDC identity tokens", + "operationId": "GetOrgClaims", + "parameters": [ + { + "in": "path", + "name": "orgID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + } + } + }, + "description": "Claims successfully fetched." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "internal server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Get org-level claims", + "tags": [ + "OIDC Token Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/org/example-value/oidc-custom-claims \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/org/example-value/oidc-custom-claims';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/org/example-value/oidc-custom-claims\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/org/example-value/oidc-custom-claims\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/org/example-value/oidc-custom-claims\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "patch": { + "description": "Creates/Updates org-level custom claims of OIDC identity tokens", + "operationId": "PatchOrgClaims", + "parameters": [ + { + "in": "path", + "name": "orgID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + } + } + }, + "description": "Claims successfully patched." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "internal server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Patch org-level claims", + "tags": [ + "OIDC Token Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/org/example-value/oidc-custom-claims \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"audience\\\": [\n \\\"example-string\\\"\n ],\n \\\"ttl\\\": \\\"example-string\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/org/example-value/oidc-custom-claims';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"audience\":[\"example-string\"],\"ttl\":\"example-string\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"audience\\\": [\\n \\\"example-string\\\"\\n ],\\n \\\"ttl\\\": \\\"example-string\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/org/example-value/oidc-custom-claims\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/org/example-value/oidc-custom-claims\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"audience\\\": [\\n \\\"example-string\\\"\\n ],\\n \\\"ttl\\\": \\\"example-string\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/org/example-value/oidc-custom-claims\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"audience\\\": [\\n \\\"example-string\\\"\\n ],\\n \\\"ttl\\\": \\\"example-string\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/org/{orgID}/project/{projectID}/oidc-custom-claims": { + "delete": { + "description": "Deletes project-level custom claims of OIDC identity tokens", + "operationId": "DeleteProjectClaims", + "parameters": [ + { + "in": "path", + "name": "orgID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "projectID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "description": "comma separated list of claims to delete. Valid values are \"audience\" and \"ttl\".", + "in": "query", + "name": "claims", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + } + } + }, + "description": "Claims successfully deleted." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "internal server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Delete project-level claims", + "tags": [ + "OIDC Token Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url \"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims?claims=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims?claims=example-value';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/org/example-value/project/example-value/oidc-custom-claims?claims=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims?claims=example-value\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims?claims=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "description": "Fetches project-level custom claims of OIDC identity tokens", + "operationId": "GetProjectClaims", + "parameters": [ + { + "in": "path", + "name": "orgID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "projectID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + } + } + }, + "description": "Claims successfully fetched." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "internal server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Get project-level claims", + "tags": [ + "OIDC Token Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/org/example-value/project/example-value/oidc-custom-claims\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "patch": { + "description": "Creates/Updates project-level custom claims of OIDC identity tokens", + "operationId": "PatchProjectClaims", + "parameters": [ + { + "in": "path", + "name": "orgID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "in": "path", + "name": "projectID", + "required": true, + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + } + } + }, + "description": "Claims successfully patched." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "internal server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Patch project-level claims", + "tags": [ + "OIDC Token Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"audience\\\": [\n \\\"example-string\\\"\n ],\n \\\"ttl\\\": \\\"example-string\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"audience\":[\"example-string\"],\"ttl\":\"example-string\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"audience\\\": [\\n \\\"example-string\\\"\\n ],\\n \\\"ttl\\\": \\\"example-string\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/org/example-value/project/example-value/oidc-custom-claims\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"audience\\\": [\\n \\\"example-string\\\"\\n ],\\n \\\"ttl\\\": \\\"example-string\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/org/example-value/project/example-value/oidc-custom-claims\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"audience\\\": [\\n \\\"example-string\\\"\\n ],\\n \\\"ttl\\\": \\\"example-string\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/owner/{ownerID}/context/{context}/decision": { + "get": { + "description": "This endpoint will return a list of decision audit logs that were made using this owner's policies.", + "operationId": "GetDecisionLogs", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Return decisions matching this decision status.", + "in": "query", + "name": "status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return decisions made after this date.", + "in": "query", + "name": "after", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "description": "Return decisions made before this date.", + "in": "query", + "name": "before", + "required": false, + "schema": { + "format": "date-time", + "type": "string" + } + }, + { + "description": "Return decisions made on this branch.", + "in": "query", + "name": "branch", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return decisions made for this project.", + "in": "query", + "name": "project_id", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Return decisions made for this build number.", + "in": "query", + "name": "build_number", + "required": false, + "schema": { + "type": "string" + } + }, + { + "description": "Sets the offset when retrieving the decisions, for paging.", + "in": "query", + "name": "offset", + "required": false, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "decision": { + "properties": { + "enabled_rules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "hard_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "reason": { + "type": "string" + }, + "soft_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "id": { + "format": "uuid", + "type": "string" + }, + "metadata": { + "properties": { + "build_number": { + "type": "integer" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ssh_rerun": { + "type": "boolean" + }, + "vcs": { + "properties": { + "branch": { + "type": "string" + }, + "origin_repository_url": { + "type": "string" + }, + "release_tag": { + "type": "string" + }, + "target_repository_url": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "policies": { + "additionalProperties": { + "maxLength": 128, + "minLength": 128, + "type": "string" + }, + "description": "policy-name-to-hash-map", + "example": { + "policy_name1": "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + "policy_name2": "5267768822ee624d48fce15ec5ca79cbd602cb7f4c2157a516556991f22ef8c7b5ef7b18d1ff41c59370efb0858651d44a936c11b7b144c48fe04df3c6a3e8da" + }, + "type": "object" + }, + "time_taken_ms": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + } + } + }, + "description": "Decision logs successfully retrieved." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Retrieves the owner's decision audit logs.", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision?status=example-value&after=example-value&before=example-value&branch=example-value&project_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&build_number=example-value&offset=123\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/decision?status=example-value&after=example-value&before=example-value&branch=example-value&project_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&build_number=example-value&offset=123';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/owner/example-value/context/example-value/decision?status=example-value&after=example-value&before=example-value&branch=example-value&project_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&build_number=example-value&offset=123\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision?status=example-value&after=example-value&before=example-value&branch=example-value&project_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&build_number=example-value&offset=123\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/decision?status=example-value&after=example-value&before=example-value&branch=example-value&project_id=497f6eca-6276-4993-bfeb-53cbbbba6f08&build_number=example-value&offset=123\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "description": "This endpoint will evaluate input data (config+metadata) against owner's stored policies and return a decision.", + "operationId": "MakeDecision", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "input": { + "type": "string" + }, + "metadata": { + "type": "object" + } + }, + "required": [ + "input" + ], + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "enabled_rules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "hard_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "reason": { + "type": "string" + }, + "soft_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + } + } + }, + "description": "Decision rendered by applying the policy against the provided data. Response will be modeled by the data and rego processed." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "context: must be a valid value.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "There was an error processing your request.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Makes a decision", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/decision \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"input\\\": \\\"example-string\\\",\n \\\"metadata\\\": {}\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/decision';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"input\":\"example-string\",\"metadata\":{}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"input\\\": \\\"example-string\\\",\\n \\\"metadata\\\": {}\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/owner/example-value/context/example-value/decision\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"input\\\": \\\"example-string\\\",\\n \\\"metadata\\\": {}\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/decision\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"input\\\": \\\"example-string\\\",\\n \\\"metadata\\\": {}\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/owner/{ownerID}/context/{context}/decision/settings": { + "get": { + "description": "This endpoint retrieves the current decision settings (eg enable/disable policy evaluation)", + "operationId": "GetDecisionSettings", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + } + }, + "description": "Decision settings successfully retrieved." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Get the decision settings", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/owner/example-value/context/example-value/decision/settings\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "patch": { + "description": "This endpoint allows modifying decision settings (eg enable/disable policy evaluation)", + "operationId": "SetDecisionSettings", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + } + }, + "description": "Decision settings successfully set." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Set the decision settings", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"enabled\\\": true\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"enabled\":true}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"enabled\\\": true\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/owner/example-value/context/example-value/decision/settings\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"enabled\\\": true\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/settings\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"enabled\\\": true\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/owner/{ownerID}/context/{context}/decision/{decisionID}": { + "get": { + "description": "This endpoint will retrieve a decision for a given decision log ID", + "operationId": "GetDecisionLog", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "decisionID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "decision": { + "properties": { + "enabled_rules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "hard_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "reason": { + "type": "string" + }, + "soft_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "id": { + "format": "uuid", + "type": "string" + }, + "metadata": { + "properties": { + "build_number": { + "type": "integer" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ssh_rerun": { + "type": "boolean" + }, + "vcs": { + "properties": { + "branch": { + "type": "string" + }, + "origin_repository_url": { + "type": "string" + }, + "release_tag": { + "type": "string" + }, + "target_repository_url": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "policies": { + "additionalProperties": { + "maxLength": 128, + "minLength": 128, + "type": "string" + }, + "description": "policy-name-to-hash-map", + "example": { + "policy_name1": "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + "policy_name2": "5267768822ee624d48fce15ec5ca79cbd602cb7f4c2157a516556991f22ef8c7b5ef7b18d1ff41c59370efb0858651d44a936c11b7b144c48fe04df3c6a3e8da" + }, + "type": "object" + }, + "time_taken_ms": { + "type": "integer" + } + }, + "type": "object" + } + } + }, + "description": "Decision log successfully retrieved." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "decision log not found", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "There was no decision log found for given decision_id, and owner_id.\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Retrieves the owner's decision audit log by given decisionID", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/owner/example-value/context/example-value/decision/example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/owner/{ownerID}/context/{context}/decision/{decisionID}/policy-bundle": { + "get": { + "description": "This endpoint will retrieve a policy bundle for a given decision log ID", + "operationId": "GetDecisionLogPolicyBundle", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "decisionID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "items": { + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "created_by": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Policy-Bundle retrieved successfully for given decision log ID" + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "decision log not found", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "There was no decision log found for given decision_id, and owner_id.\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Retrieves Policy Bundle for a given decision log ID", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value/policy-bundle \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value/policy-bundle';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/owner/example-value/context/example-value/decision/example-value/policy-bundle\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value/policy-bundle\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/decision/example-value/policy-bundle\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/owner/{ownerID}/context/{context}/policy-bundle": { + "get": { + "description": "This endpoint will retrieve a policy bundle", + "operationId": "GetPolicyBundle", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "items": { + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "created_by": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + }, + "description": "Policy-Bundle retrieved successfully." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Retrieves Policy Bundle", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/owner/example-value/context/example-value/policy-bundle\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "description": "This endpoint replaces the current policy bundle with the provided policy bundle", + "operationId": "CreatePolicyBundle", + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "dry", + "schema": { + "type": "boolean" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "policies": { + "additionalProperties": { + "description": "policy content", + "type": "string" + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "created": { + "items": { + "description": "policy names", + "type": "string" + }, + "type": "array" + }, + "deleted": { + "items": { + "description": "policy names", + "type": "string" + }, + "type": "array" + }, + "modified": { + "items": { + "description": "policy names", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Policy-Bundle diff successfully returned." + }, + "201": { + "content": { + "application/json": { + "schema": { + "properties": { + "created": { + "items": { + "description": "policy names", + "type": "string" + }, + "type": "array" + }, + "deleted": { + "items": { + "description": "policy names", + "type": "string" + }, + "type": "array" + }, + "modified": { + "items": { + "description": "policy names", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + } + }, + "description": "Policy-Bundle successfully created." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "413": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "http: request payload too large", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request exceeds the maximum payload size for policy bundles ~2.5Mib\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Creates policy bundle for the context", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url \"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle?dry=true\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"policies\\\": {}\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle?dry=true';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"policies\":{}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"policies\\\": {}\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/owner/example-value/context/example-value/policy-bundle?dry=true\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle?dry=true\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"policies\\\": {}\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle?dry=true\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"policies\\\": {}\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/owner/{ownerID}/context/{context}/policy-bundle/{policyName}": { + "get": { + "description": "This endpoint will retrieve a policy document.", + "operationId": "GetPolicyDocument", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "created_by": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "Policy retrieved successfully." + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "OwnerID: must be a valid UUID.", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is malformed (e.g, a given path parameter is invalid)\n" + }, + "401": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Unauthorized", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The request is unauthorized\n" + }, + "403": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "Forbidden", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "The user is forbidden from making this request\n" + }, + "404": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "policy not found", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "There was no policy that was found with the given owner_id and policy name.\n" + }, + "500": { + "content": { + "application/json": { + "schema": { + "properties": { + "error": { + "example": "unexpected server error", + "type": "string" + } + }, + "required": [ + "error" + ], + "type": "object" + } + } + }, + "description": "Something unexpected happened on the server." + } + }, + "summary": "Retrieves a policy document", + "tags": [ + "Policy Management" + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle/example-value \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle/example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/owner/example-value/context/example-value/policy-bundle/example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle/example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/owner/example-value/context/example-value/policy-bundle/example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "parameters": [ + { + "in": "path", + "name": "ownerID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "context", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the policy name set by the rego policy_name rule", + "in": "path", + "name": "policyName", + "required": true, + "schema": { + "type": "string" + } + } + ] + }, + "/context": { + "post": { + "summary": "Create a new context", + "description": "Creates a new context in the specified organization.", + "tags": [ + "Context" + ], + "operationId": "createContext", + "responses": { + "200": { + "description": "The new context", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the context." + }, + "name": { + "type": "string", + "description": "The user-defined name of the context." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the context was created.", + "example": "2015-09-21T17:29:21.042Z" + } + }, + "required": [ + "id", + "name", + "created_at" + ], + "title": "Context" + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The user defined name of the context." + }, + "owner": { + "additionalProperties": false, + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the owner of the context. This is the organization ID. Specify either owner/organization ID or the owner/organization slug. Find the organization ID and slug in the CircleCI web app (Organization Settings > Overview). Owner/organization slug is not supported for CircleCI server." + }, + "type": { + "type": "string", + "description": "The type of the owner. Defaults to \"organization\". Use \"account\" if you are using CircleCI server.", + "example": "organization" + } + }, + "required": [ + "id" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "slug": { + "type": "string", + "description": "A string that represents an organization. This is the organization slug. Specify either this or organization/owner ID. Find the organization ID and slug in the CircleCI web app (Organization Settings > Overview). Owner/organization slug is not supported for CircleCI server." + }, + "type": { + "type": "string", + "description": "The type of owner. Defaults to \"organization\". Accounts are only used as context owners in server and must be specified by an id instead of a slug." + } + }, + "required": [ + "slug" + ] + } + ] + } + }, + "required": [ + "name", + "owner" + ] + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/context \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"example-string\\\",\n \\\"owner\\\": null\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"example-string\",\"owner\":null}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"owner\\\": null\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/context\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"owner\\\": null\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"owner\\\": null\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "get": { + "summary": "List contexts", + "description": "List all contexts for an owner.", + "tags": [ + "Context" + ], + "operationId": "listContexts", + "responses": { + "200": { + "description": "A paginated list of contexts", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "additionalProperties": false, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the context." + }, + "name": { + "type": "string", + "description": "The user defined name of the context." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the context was created.", + "example": "2015-09-21T17:29:21.042Z" + } + }, + "required": [ + "id", + "name", + "created_at" + ], + "title": "Context" + } + }, + "next_page_token": { + "type": "string", + "nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ] + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "parameters": [ + { + "in": "query", + "name": "owner-id", + "description": "The unique ID of the owner of the context. This is the organization ID. Specify either owner/organization ID or the owner/organization slug. Find the organization ID and slug in the CircleCI web app (Organization Settings > Overview). Owner/organization slug is not supported for CircleCI server.", + "schema": { + "type": "string", + "format": "uuid" + }, + "required": false + }, + { + "in": "query", + "name": "owner-slug", + "description": "A string that represents an organization. This is the organization slug. Specify either this or organization/owner ID. Find the organization ID and slug in the CircleCI web app (Organization Settings > Overview). Owner/organization slug is not supported for CircleCI server.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "in": "query", + "name": "owner-type", + "description": "The type of the owner. Defaults to \"organization\". Use \"account\" if you are using CircleCI server.", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "page-token", + "in": "query", + "description": "A token to specify which page of results to fetch.", + "schema": { + "type": "string" + } + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/context?owner-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&owner-slug=example-value&owner-type=account&page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context?owner-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&owner-slug=example-value&owner-type=account&page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/context?owner-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&owner-slug=example-value&owner-type=account&page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context?owner-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&owner-slug=example-value&owner-type=account&page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context?owner-id=497f6eca-6276-4993-bfeb-53cbbbba6f08&owner-slug=example-value&owner-type=account&page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/context/{context_id}": { + "get": { + "summary": "Get a context", + "description": "Returns basic information about a context.", + "tags": [ + "Context" + ], + "operationId": "getContext", + "responses": { + "200": { + "description": "The context", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the context." + }, + "name": { + "type": "string", + "description": "The user defined name of the context." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the context was created.", + "example": "2015-09-21T17:29:21.042Z" + } + }, + "required": [ + "id", + "name", + "created_at" + ], + "title": "Context" + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Delete a context", + "description": "Delete a context by its ID. Will also delete all environment variables inside the context.", + "tags": [ + "Context" + ], + "operationId": "deleteContext", + "responses": { + "200": { + "description": "A confirmation message", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/context/{context_id}/environment-variable": { + "get": { + "summary": "List environment variables", + "description": "List information about environment variables in a context, not including their values.", + "tags": [ + "Context" + ], + "operationId": "listEnvironmentVariablesFromContext", + "responses": { + "200": { + "description": "A paginated list of environment variables", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "variable": { + "type": "string", + "description": "The name of the environment variable", + "example": "POSTGRES_USER" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the environment variable was created.", + "example": "2015-09-21T17:29:21.042Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the environment variable was updated", + "example": "2015-09-21T17:29:21.042Z" + }, + "context_id": { + "type": "string", + "format": "uuid", + "description": "ID of the context (UUID)" + } + }, + "required": [ + "variable", + "created_at", + "updated_at", + "context_id" + ] + } + }, + "next_page_token": { + "type": "string", + "nullable": true, + "description": "A token to pass as a `page-token` query parameter to return the next page of results." + } + }, + "required": [ + "items", + "next_page_token" + ] + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page-token", + "in": "query", + "description": "A token to specify which page of results to fetch.", + "schema": { + "type": "string" + } + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable?page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable?page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable?page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable?page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable?page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/context/{context_id}/environment-variable/{env_var_name}": { + "put": { + "summary": "Add or update an environment variable", + "description": "Create or update an environment variable within a context. Returns information about the environment variable, not including its value.", + "tags": [ + "Context" + ], + "operationId": "addEnvironmentVariableToContext", + "responses": { + "200": { + "description": "The new environment variable", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "anyOf": [ + { + "type": "object", + "additionalProperties": false, + "properties": { + "variable": { + "type": "string", + "description": "The name of the environment variable", + "example": "POSTGRES_USER" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the environment variable was created.", + "example": "2015-09-21T17:29:21.042Z" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the environment variable was updated", + "example": "2015-09-21T17:29:21.042Z" + }, + "context_id": { + "type": "string", + "format": "uuid", + "description": "ID of the context (UUID)" + } + }, + "required": [ + "variable", + "created_at", + "updated_at", + "context_id" + ] + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + ] + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "env_var_name", + "description": "The name of the environment variable.", + "example": "POSTGRES_USER", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "value": { + "type": "string", + "description": "The value of the environment variable", + "example": "some-secret-value" + } + }, + "required": [ + "value" + ] + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PUT \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"value\\\": \\\"some-secret-value\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER';\n const options = {\n method: 'PUT',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"value\":\"some-secret-value\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"value\\\": \\\"some-secret-value\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PUT\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"value\\\": \\\"some-secret-value\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"PUT\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Put.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"value\\\": \\\"some-secret-value\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "summary": "Remove an environment variable", + "description": "Delete an environment variable from a context.", + "tags": [ + "Context" + ], + "operationId": "deleteEnvironmentVariableFromContext", + "responses": { + "200": { + "description": "A confirmation message", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "A human-readable message" + } + }, + "required": [ + "message" + ], + "description": "message response", + "title": "MessageResponse" + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "env_var_name", + "description": "The name of the environment variable.", + "example": "POSTGRES_USER", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/environment-variable/POSTGRES_USER\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/context/{context_id}/restrictions": { + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "get": { + "operationId": "getContextRestrictions", + "summary": "Get context restrictions", + "description": "Gets a list of project and expression restrictions associated with a context.", + "tags": [ + "Context" + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "additionalProperties": false, + "properties": { + "context_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the context" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the restriction" + }, + "project_id": { + "type": "string", + "format": "uuid", + "description": "Deprecated - For \"project\" restrictions read the project ID from\n\"restriction_value\" instead.\n\nUUID of the project used in a project restriction.\n", + "deprecated": true + }, + "name": { + "type": "string", + "description": "Contains a human-readable reference for the restriction. For\n\"project\" restrictions this is the name of the project.\n\nMay be null.\n" + }, + "restriction_type": { + "type": "string", + "description": "Type of the restriction" + }, + "restriction_value": { + "type": "string", + "description": "Value used to evaluate the restriction" + } + } + } + }, + "next_page_token": { + "type": "string", + "nullable": true, + "description": "Token that can be used to retrieve next page of results" + } + } + } + } + } + }, + "400": { + "description": "Context ID provided is invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "context_id is invalid." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "operationId": "createContextRestriction", + "summary": "Create context restriction", + "description": "Creates project or expression restriction on a context.", + "tags": [ + "Context" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "restriction_type": { + "type": "string", + "description": "Type of the restriction." + }, + "restriction_value": { + "type": "string", + "description": "Value used to evaluate the restriction. If the `restriction_type`\nis `project`, this will be the project UUID. If the `restriction_type`\nis `expression`, this will be the expression rule.\n" + } + } + }, + "examples": { + "project_restriction": { + "summary": "project restriction", + "value": { + "restriction_type": "project", + "restriction_value": "405d8375-3514-403b-8c43-83ae74cfe0e9" + } + }, + "expression_restriction": { + "summary": "expression restriction", + "value": { + "restriction_type": "expression", + "restriction_value": "pipeline.git.branch == \"main\"" + } + }, + "group_restriction": { + "summary": "group restriction", + "value": { + "restriction_type": "group", + "restriction_value": "30865957-99e1-4b69-8c9f-d83a91756f89" + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the project restriction" + }, + "project_id": { + "type": "string", + "format": "uuid", + "description": "Deprecated - For \"project\" restrictions read the project ID from\n\"restriction_value\" instead.\n\nUUID of the project used in a project restriction.\n" + }, + "name": { + "type": "string", + "description": "Contains a human-readable reference for the restriction. For\n\"project\" restrictions this is the name of the project.\n\nMay be null.\n" + }, + "restriction_type": { + "type": "string", + "description": "Type of the restriction" + }, + "restriction_value": { + "type": "string", + "description": "Value used to evaluate the restriction" + } + } + }, + "examples": { + "project_restriction": { + "summary": "project restriction", + "value": { + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9", + "name": "project-name", + "restriction_type": "project", + "restriction_value": "405d8375-3514-403b-8c43-83ae74cfe0e9" + } + }, + "expression_restriction": { + "summary": "expression restriction", + "value": { + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "name": "", + "restriction_type": "expression", + "restriction_value": "pipeline.git.branch == \"main\"" + } + }, + "group_restriction": { + "summary": "group restriction", + "value": { + "id": "30865957-99e1-4b69-8c9f-d83a91756f89", + "name": "A Group In My Organization", + "restriction_type": "group", + "restriction_value": "30865957-99e1-4b69-8c9f-d83a91756f89" + } + } + } + } + } + }, + "400": { + "description": "Bad request.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_restriction": { + "summary": "Invalid restriction", + "value": { + "message": "This restriction cannot be applied to this context." + } + }, + "invalid_access": { + "summary": "Project doesn't exist, or insufficient credentials", + "value": { + "message": "Project does not exist, or user does not have access to this project." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "409": { + "description": "Request conflict.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "restriction_conflict": { + "summary": "Restriction conflict", + "value": { + "message": "The restriction you're trying to add already exists." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"restriction_type\\\": \\\"project\\\",\n \\\"restriction_value\\\": \\\"example-string\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"restriction_type\":\"project\",\"restriction_value\":\"example-string\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"restriction_type\\\": \\\"project\\\",\\n \\\"restriction_value\\\": \\\"example-string\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"restriction_type\\\": \\\"project\\\",\\n \\\"restriction_value\\\": \\\"example-string\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"restriction_type\\\": \\\"project\\\",\\n \\\"restriction_value\\\": \\\"example-string\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/context/{context_id}/restrictions/{restriction_id}": { + "parameters": [ + { + "name": "context_id", + "description": "An opaque identifier of a context.", + "example": "be8bb2e3-c3d6-4098-89f4-572ff976ba9a", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "restriction_id", + "description": "An opaque identifier of a context restriction.", + "example": "1c23d2cb-07b1-4a28-8af3-e369732050ed", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "delete": { + "operationId": "deleteContextRestriction", + "summary": "Delete context restriction", + "description": "Deletes a project, expression or group restriction from a context.", + "tags": [ + "Context" + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "Response message" + } + } + }, + "examples": { + "successful_delete": { + "summary": "Successful deletion of restriction", + "value": { + "message": "Context restriction deleted." + } + } + } + } + } + }, + "400": { + "description": "Context restriction ID provided is invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "restriction_id is invalid." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions/1c23d2cb-07b1-4a28-8af3-e369732050ed \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions/1c23d2cb-07b1-4a28-8af3-e369732050ed';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions/1c23d2cb-07b1-4a28-8af3-e369732050ed\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions/1c23d2cb-07b1-4a28-8af3-e369732050ed\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/context/be8bb2e3-c3d6-4098-89f4-572ff976ba9a/restrictions/1c23d2cb-07b1-4a28-8af3-e369732050ed\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{provider}/{organization}/{project}": { + "parameters": [ + { + "name": "provider", + "description": "The first segment of the slash-separated project slug, as shown in Project Settings > Overview.", + "example": "gh", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "organization", + "description": "The second segment of the slash-separated project slug, as shown in Project Settings > Overview. Depending on the organization type, this may be the org name (e.g. `my-org`) or an ID (e.g. `43G3lM5RtfFE7v5sa4nWAU`).", + "example": "CircleCI-Public", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project", + "description": "The third segment of the slash-separated project slug, as shown in Project Settings > Overview. Depending on the organization type, this may be the project name (e.g. `my-project`) or an ID (e.g. `44n9wujWcTnVZ2b5S8Fnat`).", + "example": "api-preview-docs", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "post": { + "operationId": "createProject1", + "summary": "⚠️ Create a project", + "description": "__[DEPRECATED] This endpoint is replaced by [organization/{org-slug-or-id}/project](https://circleci.com/docs/api/v2/index.html#tag/Project/operation/createProject) and documentation will be removed on August 1st, 2025.__ Creates a new CircleCI project, and returns a list of the default advanced settings. Can only be called on a repo with a main branch and an existing config.yml file. Not yet available to projects that use GitLab or GitHub App.", + "tags": [ + "Project" + ], + "responses": { + "201": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "advanced": { + "type": "object", + "additionalProperties": false, + "properties": { + "autocancel_builds": { + "type": "boolean", + "description": "Except for the default branch, cancel running pipelines on a branch when a new pipeline starts on that branch." + }, + "build_fork_prs": { + "type": "boolean", + "description": "Run builds for pull requests from forks." + }, + "build_prs_only": { + "type": "boolean", + "description": "Once enabled, we will only build branches that have associated pull requests open." + }, + "disable_ssh": { + "type": "boolean", + "description": "When set to true, job re-runs with SSH debugging access will be disabled for the project." + }, + "forks_receive_secret_env_vars": { + "type": "boolean", + "description": "Run builds for forked pull requests with this project's configuration, environment variables, and secrets." + }, + "oss": { + "type": "boolean", + "description": "Free and Open Source. Enabling this grants additional credits, and lets others see your builds, both through the web UI and the API." + }, + "set_github_status": { + "type": "boolean", + "description": "Report the status of every pushed commit to GitHub's status API. Updates reported per job." + }, + "setup_workflows": { + "type": "boolean", + "description": "Enabling allows you to conditionally trigger configurations outside of the primary `.circleci` parent directory." + }, + "write_settings_requires_admin": { + "type": "boolean", + "description": "Whether updating these settings requires a user to be an organization administrator. When disabled, updating settings can be done by any member." + }, + "pr_only_branch_overrides": { + "type": "array", + "items": { + "type": "string" + }, + "description": "This field is used in conjunction with the `build_prs_only`, it allows you to specify a list of branches that will always triger a build. The value passed will overwrite the existing value." + } + } + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Either a branch or a project were not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "branch_not_found": { + "summary": "Branch not found, unable to trigger pipeline.", + "value": { + "message": "Branch not found." + } + }, + "project_not_found": { + "summary": "Project not found, e.g. GitHub repo.", + "value": { + "message": "Project not found." + } + } + } + } + } + }, + "405": { + "description": "Create projects using the API is currently supported for classic Github OAuth and Bitbucket projects only.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Create projects using the API is currently supported for classic Github OAuth and Bitbucket projects only." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs';\n const options = {method: 'POST', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs\"\n\n\treq, _ := http.NewRequest(\"POST\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{provider}/{organization}/{project}/settings": { + "parameters": [ + { + "name": "provider", + "description": "The first segment of the slash-separated project slug, as shown in Project Settings > Overview.", + "example": "gh", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "organization", + "description": "The second segment of the slash-separated project slug, as shown in Project Settings > Overview. Depending on the organization type, this may be the org name (e.g. `my-org`) or an ID (e.g. `43G3lM5RtfFE7v5sa4nWAU`).", + "example": "CircleCI-Public", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project", + "description": "The third segment of the slash-separated project slug, as shown in Project Settings > Overview. Depending on the organization type, this may be the project name (e.g. `my-project`) or an ID (e.g. `44n9wujWcTnVZ2b5S8Fnat`).", + "example": "api-preview-docs", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "get": { + "operationId": "getProjectSettings", + "summary": "🧪 Get project settings", + "description": "[__EXPERIMENTAL__] Returns a list of the advanced settings for a CircleCI project, whether enabled (true) or not (false).", + "tags": [ + "Project" + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "advanced": { + "type": "object", + "additionalProperties": false, + "properties": { + "autocancel_builds": { + "type": "boolean", + "description": "Except for the default branch, cancel running pipelines on a branch when a new pipeline starts on that branch." + }, + "build_fork_prs": { + "type": "boolean", + "description": "Run builds for pull requests from forks." + }, + "build_prs_only": { + "type": "boolean", + "description": "Once enabled, we will only build branches that have associated pull requests open." + }, + "disable_ssh": { + "type": "boolean", + "description": "When set to true, job re-runs with SSH debugging access will be disabled for the project." + }, + "forks_receive_secret_env_vars": { + "type": "boolean", + "description": "Run builds for forked pull requests with this project's configuration, environment variables, and secrets." + }, + "oss": { + "type": "boolean", + "description": "Free and Open Source. Enabling this grants additional credits, and lets others see your builds, both through the web UI and the API." + }, + "set_github_status": { + "type": "boolean", + "description": "Report the status of every pushed commit to GitHub's status API. Updates reported per job." + }, + "setup_workflows": { + "type": "boolean", + "description": "Enabling allows you to conditionally trigger configurations outside of the primary `.circleci` parent directory." + }, + "write_settings_requires_admin": { + "type": "boolean", + "description": "Whether updating these settings requires a user to be an organization administrator. When disabled, updating settings can be done by any member." + }, + "pr_only_branch_overrides": { + "type": "array", + "items": { + "type": "string" + }, + "description": "This field is used in conjunction with the `build_prs_only`, it allows you to specify a list of branches that will always triger a build. The value passed will overwrite the existing value." + } + } + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Insufficient credentials for a private project, OR the organization, project, or repository does not exist.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Project not found." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "patch": { + "operationId": "patchProjectSettings", + "summary": "🧪 Update project settings", + "description": "[__EXPERIMENTAL__] Updates one or more of the advanced settings for a CircleCI project.", + "tags": [ + "Project" + ], + "requestBody": { + "description": "The setting(s) to update, including one or more fields in the JSON object. Note that `oss: true` will only be set on projects whose underlying repositories are actually open source.", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "advanced": { + "type": "object", + "additionalProperties": false, + "properties": { + "autocancel_builds": { + "type": "boolean", + "description": "Except for the default branch, cancel running pipelines on a branch when a new pipeline starts on that branch." + }, + "build_fork_prs": { + "type": "boolean", + "description": "Run builds for pull requests from forks." + }, + "build_prs_only": { + "type": "boolean", + "description": "Once enabled, we will only build branches that have associated pull requests open." + }, + "disable_ssh": { + "type": "boolean", + "description": "When set to true, job re-runs with SSH debugging access will be disabled for the project." + }, + "forks_receive_secret_env_vars": { + "type": "boolean", + "description": "Run builds for forked pull requests with this project's configuration, environment variables, and secrets." + }, + "oss": { + "type": "boolean", + "description": "Free and Open Source. Enabling this grants additional credits, and lets others see your builds, both through the web UI and the API." + }, + "set_github_status": { + "type": "boolean", + "description": "Report the status of every pushed commit to GitHub's status API. Updates reported per job." + }, + "setup_workflows": { + "type": "boolean", + "description": "Enabling allows you to conditionally trigger configurations outside of the primary `.circleci` parent directory." + }, + "write_settings_requires_admin": { + "type": "boolean", + "description": "Whether updating these settings requires a user to be an organization administrator. When disabled, updating settings can be done by any member." + }, + "pr_only_branch_overrides": { + "type": "array", + "items": { + "type": "string" + }, + "description": "This field is used in conjunction with the `build_prs_only`, it allows you to specify a list of branches that will always triger a build. The value passed will overwrite the existing value." + } + } + } + } + }, + "example": { + "advanced": { + "autocancel_builds": false, + "build_prs_only": true, + "pr_only_branch_overrides": [ + "main" + ] + } + } + } + } + }, + "responses": { + "200": { + "description": "Successful response. Always includes the full advanced settings object. Returned even when the provided updates match the existing settings, but can also be returned when `oss: true` fails to set.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "advanced": { + "type": "object", + "additionalProperties": false, + "properties": { + "autocancel_builds": { + "type": "boolean", + "description": "Except for the default branch, cancel running pipelines on a branch when a new pipeline starts on that branch." + }, + "build_fork_prs": { + "type": "boolean", + "description": "Run builds for pull requests from forks." + }, + "build_prs_only": { + "type": "boolean", + "description": "Once enabled, we will only build branches that have associated pull requests open." + }, + "disable_ssh": { + "type": "boolean", + "description": "When set to true, job re-runs with SSH debugging access will be disabled for the project." + }, + "forks_receive_secret_env_vars": { + "type": "boolean", + "description": "Run builds for forked pull requests with this project's configuration, environment variables, and secrets." + }, + "oss": { + "type": "boolean", + "description": "Free and Open Source. Enabling this grants additional credits, and lets others see your builds, both through the web UI and the API." + }, + "set_github_status": { + "type": "boolean", + "description": "Report the status of every pushed commit to GitHub's status API. Updates reported per job." + }, + "setup_workflows": { + "type": "boolean", + "description": "Enabling allows you to conditionally trigger configurations outside of the primary `.circleci` parent directory." + }, + "write_settings_requires_admin": { + "type": "boolean", + "description": "Whether updating these settings requires a user to be an organization administrator. When disabled, updating settings can be done by any member." + }, + "pr_only_branch_overrides": { + "type": "array", + "items": { + "type": "string" + }, + "description": "This field is used in conjunction with the `build_prs_only`, it allows you to specify a list of branches that will always triger a build. The value passed will overwrite the existing value." + } + } + } + } + } + } + } + }, + "400": { + "description": "Request is malformed, e.g. with improperly encoded JSON", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_json": { + "summary": "Invalid JSON body", + "value": { + "message": "Invalid JSON body." + } + }, + "too_many_branch_overrides": { + "summary": "More than 100 branches sent for `pr_only_branch_overrides`", + "value": { + "message": "Field 'pr_only_branch_overrides' only supports up to 100 branches." + } + }, + "no_json": { + "summary": "Empty JSON request body", + "value": { + "message": "No JSON fields found." + } + }, + "unexpected_field": { + "summary": "Incorrect root field name", + "value": { + "message": "Unexpected JSON field 'incorrect'" + } + }, + "unknown_setting": { + "summary": "Incorrect setting name", + "value": { + "message": "Unknown advanced setting 'incorrect'." + } + }, + "incorrect_type": { + "summary": "Incorrect setting type", + "value": { + "message": "Setting 'autocancel_builds' must be boolean." + } + }, + "oss": { + "summary": "Incorrect OSS value for project", + "value": { + "message": "Feature flag 'oss' is not settable for this project." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Insufficient credentials for a private project, OR the organization, project, or repository does not exist.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Project not found." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"advanced\\\": {\n \\\"autocancel_builds\\\": true,\n \\\"build_fork_prs\\\": true,\n \\\"build_prs_only\\\": true\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"advanced\":{\"autocancel_builds\":true,\"build_fork_prs\":true,\"build_prs_only\":true}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"advanced\\\": {\\n \\\"autocancel_builds\\\": true,\\n \\\"build_fork_prs\\\": true,\\n \\\"build_prs_only\\\": true\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"advanced\\\": {\\n \\\"autocancel_builds\\\": true,\\n \\\"build_fork_prs\\\": true,\\n \\\"build_prs_only\\\": true\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/settings\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"advanced\\\": {\\n \\\"autocancel_builds\\\": true,\\n \\\"build_fork_prs\\\": true,\\n \\\"build_prs_only\\\": true\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organizations/{org_id}/groups": { + "parameters": [ + { + "name": "org_id", + "description": "An opaque identifier of an organization.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "get": { + "operationId": "getOrganizationGroups", + "summary": "Groups in an organization", + "description": "Get all the groups in an organization.", + "tags": [ + "Groups" + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "The number of results per page.", + "schema": { + "type": "integer" + } + }, + { + "name": "page-token", + "in": "query", + "description": "A token to specify which page of results to fetch.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully get all the groups in an organization. Results are paginated.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for group" + }, + "name": { + "type": "string", + "description": "Name of group" + }, + "description": { + "type": "string", + "description": "Description field on group" + } + } + } + }, + "next_page_token": { + "type": "string", + "nullable": true + }, + "total_count": { + "type": "integer" + } + } + }, + "examples": { + "groups": { + "summary": "A list of sample groups", + "value": { + "items": [ + { + "id": "bdbe5e8d-50a5-4f73-a917-074592949844", + "name": "Project B Editors", + "description": "This group has the ability to edit settings on Project B." + }, + { + "id": "70dbc16f-a6b9-4c32-b258-4a61a861c24f", + "name": "Project MLOps Editors", + "description": "This group has the ability to edit settings on ML Ops Projects." + } + ], + "next_page_token": "CiRkNjVjY2ZiMy04OGFlLTQ3YjUtYWFjNi0wZDRkNDYwNmQ5ZjYQChoDbmls" + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups?limit=123&page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups?limit=123&page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups?limit=123&page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups?limit=123&page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups?limit=123&page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "operationId": "createOrganizationGroup", + "summary": "Create Groups", + "description": "Create a new group under the organization.", + "tags": [ + "Groups" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Name of the group" + }, + "description": { + "type": "string", + "description": "Description to describe the group" + } + }, + "required": [ + "name" + ] + }, + "examples": { + "group": { + "summary": "Create a new group", + "value": { + "name": "Project A Editors", + "description": "Users in this group have edit access to Project A" + } + } + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successful creation of a group.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for group" + }, + "name": { + "type": "string", + "description": "Name of group" + }, + "description": { + "type": "string", + "description": "Description field on group" + } + } + }, + "examples": { + "group": { + "summary": "A sample group", + "value": { + "id": "9e5e5f87-3e87-47ea-be0f-37265b965d6e", + "name": "Project A Editors", + "description": "Users in this group have edit access to Project A" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "409": { + "description": "A conflict has occurred while attempting to create the resource.\n", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "max_groups": { + "summary": "Max number of groups reached", + "value": { + "message": "Failed to create group, reached max number of groups for this organization." + } + }, + "name_already_taken": { + "summary": "Group name already taken", + "value": { + "message": "Failed to create group, group already exists." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"example-string\\\",\n \\\"description\\\": \\\"example-string\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"example-string\",\"description\":\"example-string\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"description\\\": \\\"example-string\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"description\\\": \\\"example-string\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"example-string\\\",\\n \\\"description\\\": \\\"example-string\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organizations/{org_id}/groups/{group_id}": { + "parameters": [ + { + "name": "org_id", + "description": "An opaque identifier of an organization.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "group_id", + "description": "An opaque identifier of a group.", + "example": "39f660db-f49b-417e-ad79-2769ba29faf7", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "get": { + "operationId": "getGroup", + "summary": "A group in an organization", + "description": "Get details for a group in an organization.", + "tags": [ + "Groups" + ], + "responses": { + "200": { + "description": "Successfully gets a group. Members not included.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for group" + }, + "name": { + "type": "string", + "description": "Name of group" + }, + "description": { + "type": "string", + "description": "Description field on group" + } + } + }, + "examples": { + "group": { + "summary": "A sample group", + "value": { + "id": "bdbe5e8d-50a5-4f73-a917-074592949844", + "name": "Project A Editors", + "description": "Users can edit Project A settings." + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "operationId": "deleteGroup", + "summary": "Delete a group", + "description": "Delete a group in an organization. This will remove all members from the group as well, and the subsequent role grants tied to the group.", + "tags": [ + "Groups" + ], + "responses": { + "200": { + "description": "Successful deletion of a group.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Group deleted." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "403": { + "description": "None or insufficient credentials provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Permission denied." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/groups/39f660db-f49b-417e-ad79-2769ba29faf7\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organizations/{org_id}/usage_export_job": { + "parameters": [ + { + "name": "org_id", + "description": "An opaque identifier of an organization.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "post": { + "operationId": "createUsageExport", + "summary": "Create a usage export", + "description": "Submits a request to create a usage export for an organization.", + "tags": [ + "Usage" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "type": "object", + "properties": { + "start": { + "type": "string", + "format": "date-time", + "description": "The start date & time (inclusive) of the range from which data will be pulled. Must be no more than one year ago." + }, + "end": { + "type": "string", + "format": "date-time", + "description": "The end date & time (inclusive) of the range from which data will be pulled. Must be no more than 31 days after `start`." + }, + "shared_org_ids": { + "type": "array", + "items": { + "type": "string", + "format": "uuid", + "description": "Additional shared org IDs to to include data for in the generated usage export." + } + } + }, + "required": [ + "start", + "end" + ] + } + } + } + }, + "responses": { + "201": { + "description": "Usage export created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "usage_export_job_id": { + "type": "string", + "format": "uuid" + }, + "state": { + "type": "string" + }, + "start": { + "type": "string", + "format": "date-time" + }, + "end": { + "type": "string", + "format": "date-time" + }, + "download_urls": { + "description": "A list of pre signed urls that the client can use to download the results of a Usage Export.", + "type": "array", + "items": { + "additionalProperties": false, + "type": "string", + "format": "uri" + } + } + }, + "required": [ + "usage_export_job_id", + "state", + "start", + "end", + "download_urls" + ] + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"start\\\": \\\"example-string\\\",\n \\\"end\\\": \\\"example-string\\\",\n \\\"shared_org_ids\\\": [\n \\\"example-string\\\"\n ]\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"start\":\"example-string\",\"end\":\"example-string\",\"shared_org_ids\":[\"example-string\"]}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"start\\\": \\\"example-string\\\",\\n \\\"end\\\": \\\"example-string\\\",\\n \\\"shared_org_ids\\\": [\\n \\\"example-string\\\"\\n ]\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"start\\\": \\\"example-string\\\",\\n \\\"end\\\": \\\"example-string\\\",\\n \\\"shared_org_ids\\\": [\\n \\\"example-string\\\"\\n ]\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"start\\\": \\\"example-string\\\",\\n \\\"end\\\": \\\"example-string\\\",\\n \\\"shared_org_ids\\\": [\\n \\\"example-string\\\"\\n ]\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/organizations/{org_id}/usage_export_job/{usage_export_job_id}": { + "parameters": [ + { + "name": "org_id", + "description": "An opaque identifier of an organization.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "usage_export_job_id", + "description": "An opaque identifier of a usage export job.", + "example": "e8235eed-f121-4ae3-9c72-2719d6572818", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "get": { + "operationId": "getUsageExport", + "summary": "Get a usage export", + "description": "Gets a usage export for an organization.", + "tags": [ + "Usage" + ], + "responses": { + "200": { + "description": "Usage export fetched successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "usage_export_job_id": { + "type": "string", + "format": "uuid" + }, + "state": { + "type": "string" + }, + "download_urls": { + "description": "A list of pre signed urls that the client can use to download the results of a Usage Export.", + "type": "array", + "items": { + "additionalProperties": false, + "type": "string", + "format": "uri" + } + }, + "error_reason": { + "type": "string" + } + }, + "required": [ + "usage_export_job_id", + "state", + "download_urls" + ] + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "429": { + "description": "API rate limits exceeded.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Rate limit exceeded." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job/e8235eed-f121-4ae3-9c72-2719d6572818 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job/e8235eed-f121-4ae3-9c72-2719d6572818';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job/e8235eed-f121-4ae3-9c72-2719d6572818\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job/e8235eed-f121-4ae3-9c72-2719d6572818\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/organizations/b9291e0d-a11e-41fb-8517-c545388b5953/usage_export_job/e8235eed-f121-4ae3-9c72-2719d6572818\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/project/{provider}/{organization}/{project}/pipeline/run": { + "post": { + "operationId": "triggerPipelineRun", + "summary": "[Recommended] Trigger a new pipeline", + "description": "Trigger a pipeline given a pipeline definition ID. Supports all integrations except GitLab.\n\nThe slash-separated project slug is shown in Project Settings > Overview.\n\nDepending on the organization type, the project slug may have a human-readable format (`vcs_type/org_name/project_name`)\nor be an opaque string (e.g. `circleci/43G3lM5RtfFE7v5sa4nWAU/44n9wujWcTnVZ2b5S8Fnat`).", + "tags": [ + "Pipeline" + ], + "parameters": [ + { + "name": "provider", + "description": "The first segment of the slash-separated project slug, as shown in Project Settings > Overview.", + "example": "gh", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "organization", + "description": "The second segment of the slash-separated project slug, as shown in Project Settings > Overview. Depending on the organization type, this may be the org name (e.g. `my-org`) or an ID (e.g. `43G3lM5RtfFE7v5sa4nWAU`).", + "example": "CircleCI-Public", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "project", + "description": "The third segment of the slash-separated project slug, as shown in Project Settings > Overview. Depending on the organization type, this may be the project name (e.g. `my-project`) or an ID (e.g. `44n9wujWcTnVZ2b5S8Fnat`).", + "example": "api-preview-docs", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "definition_id": { + "type": "string", + "format": "uuid", + "description": "The unique id for the pipeline definition. This can be found in the page Project Settings > Pipelines.", + "example": "2338d0ae-5541-4bbf-88a2-55e9f7281f80" + }, + "config": { + "type": "object", + "additionalProperties": false, + "example": { + "branch": "main" + }, + "properties": { + "branch": { + "type": "string", + "example": "main", + "description": "The branch that should be used to fetch the config file.\nNote that branch and tag are mutually exclusive.\nTo trigger a pipeline for a PR by number use pull//head for the PR ref or pull//merge for the merge ref (GitHub only)\n" + }, + "tag": { + "type": "string", + "example": "v2", + "description": "The tag that should be used to fetch the config file.\nThe commit that this tag points to is used for the pipeline.\nNote that branch and tag are mutually exclusive.\n" + } + } + }, + "checkout": { + "type": "object", + "additionalProperties": false, + "example": { + "tag": "v2" + }, + "properties": { + "branch": { + "type": "string", + "example": "main", + "description": "The branch that should be used to check out code on a checkout step.\nNote that branch and tag are mutually exclusive.\nTo trigger a pipeline for a PR by number use pull//head for the PR ref or pull//merge for the merge ref (GitHub only)\n" + }, + "tag": { + "type": "string", + "example": "v2", + "description": "The tag that should be used to check out code on a checkout step.\nThe commit that this tag points to is used for the pipeline. Note that branch and tag are mutually exclusive.\n" + } + } + }, + "parameters": { + "type": "object", + "additionalProperties": true, + "description": "An object containing pipeline parameters and their values.\nPipeline parameters have the following size limits: 100 max entries, 128 maximum key length, 512 maximum value length.\n", + "example": { + "example_param": "my value", + "example_param2": true, + "example_param3": 3 + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successful response with no created pipeline.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "A message indicating the reason why a pipeline was not triggered", + "example": "Ignoring pipeline due to CI skip in the commit" + } + } + } + } + } + }, + "201": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "state": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "number": { + "type": "integer", + "example": 25 + }, + "id": { + "type": "string", + "format": "uuid" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/run \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"definition_id\\\": \\\"2338d0ae-5541-4bbf-88a2-55e9f7281f80\\\",\n \\\"config\\\": {\n \\\"branch\\\": \\\"main\\\"\n },\n \\\"checkout\\\": {\n \\\"tag\\\": \\\"v2\\\"\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/run';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"definition_id\":\"2338d0ae-5541-4bbf-88a2-55e9f7281f80\",\"config\":{\"branch\":\"main\"},\"checkout\":{\"tag\":\"v2\"}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"definition_id\\\": \\\"2338d0ae-5541-4bbf-88a2-55e9f7281f80\\\",\\n \\\"config\\\": {\\n \\\"branch\\\": \\\"main\\\"\\n },\\n \\\"checkout\\\": {\\n \\\"tag\\\": \\\"v2\\\"\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/run\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/run\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"definition_id\\\": \\\"2338d0ae-5541-4bbf-88a2-55e9f7281f80\\\",\\n \\\"config\\\": {\\n \\\"branch\\\": \\\"main\\\"\\n },\\n \\\"checkout\\\": {\\n \\\"tag\\\": \\\"v2\\\"\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline/run\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"definition_id\\\": \\\"2338d0ae-5541-4bbf-88a2-55e9f7281f80\\\",\\n \\\"config\\\": {\\n \\\"branch\\\": \\\"main\\\"\\n },\\n \\\"checkout\\\": {\\n \\\"tag\\\": \\\"v2\\\"\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/projects/{project_id}/pipeline-definitions": { + "get": { + "operationId": "listPipelineDefinitions", + "summary": "List pipeline definitions", + "description": "List all pipeline definitions for a given project. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Pipeline Definition" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline definition." + }, + "name": { + "type": "string", + "example": "some pipeline", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "some pipeline description", + "description": "The description of the pipeline definition." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline definition was created." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "operationId": "createPipelineDefinition", + "summary": "Create pipeline definition", + "description": "Create a pipeline definition for a given project. Currently only supported for pipeline definitions where `config_source.provider` is `github_app`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Pipeline Definition" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "example": "Some pipeline name", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "Some pipeline description", + "description": "The description of the pipeline definition." + }, + "config_source": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "description": "Config source for external providers (repo required)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app` is the only supported external provider." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + }, + "required": [ + "external_id" + ] + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + }, + "required": [ + "provider", + "repo", + "file_path" + ] + }, + { + "type": "object", + "additionalProperties": false, + "description": "Config source for CircleCI provider (no repo required)", + "properties": { + "provider": { + "type": "string", + "description": "The integration provider for this resource." + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + }, + "required": [ + "provider", + "file_path" + ] + } + ] + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app` is the only supported value." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + }, + "required": [ + "external_id" + ] + } + }, + "required": [ + "provider", + "repo" + ] + } + }, + "required": [ + "name", + "config_source", + "checkout_source" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline definition." + }, + "name": { + "type": "string", + "example": "some pipeline", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "some pipeline description", + "description": "The description of the pipeline definition." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline definition was created." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"Some pipeline name\\\",\n \\\"description\\\": \\\"Some pipeline description\\\",\n \\\"config_source\\\": null,\n \\\"checkout_source\\\": {\n \\\"provider\\\": \\\"github_app\\\",\n \\\"repo\\\": {\n \\\"external_id\\\": \\\"some-repo-id\\\"\n }\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"Some pipeline name\",\"description\":\"Some pipeline description\",\"config_source\":null,\"checkout_source\":{\"provider\":\"github_app\",\"repo\":{\"external_id\":\"some-repo-id\"}}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"Some pipeline name\\\",\\n \\\"description\\\": \\\"Some pipeline description\\\",\\n \\\"config_source\\\": null,\\n \\\"checkout_source\\\": {\\n \\\"provider\\\": \\\"github_app\\\",\\n \\\"repo\\\": {\\n \\\"external_id\\\": \\\"some-repo-id\\\"\\n }\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"Some pipeline name\\\",\\n \\\"description\\\": \\\"Some pipeline description\\\",\\n \\\"config_source\\\": null,\\n \\\"checkout_source\\\": {\\n \\\"provider\\\": \\\"github_app\\\",\\n \\\"repo\\\": {\\n \\\"external_id\\\": \\\"some-repo-id\\\"\\n }\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"Some pipeline name\\\",\\n \\\"description\\\": \\\"Some pipeline description\\\",\\n \\\"config_source\\\": null,\\n \\\"checkout_source\\\": {\\n \\\"provider\\\": \\\"github_app\\\",\\n \\\"repo\\\": {\\n \\\"external_id\\\": \\\"some-repo-id\\\"\\n }\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}": { + "get": { + "operationId": "getPipelineDefinition", + "summary": "Get pipeline definition", + "description": "Get details for a pipeline definition. Currently only supported for pipeline definitions where `config_source.provider` is `github_app`, `github_oauth`, `bitbucket_dc`, `bitbucket_oauth` or `gitlab`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Pipeline Definition" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "pipeline_definition_id", + "description": "An opaque identifier of a pipeline definition.", + "example": "6cb29b00-8e02-4357-8bc0-313983bf1f46", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline definition." + }, + "name": { + "type": "string", + "example": "some pipeline", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "some pipeline description", + "description": "The description of the pipeline definition." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline definition was created." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "patch": { + "operationId": "updatePipelineDefinition", + "summary": "Update pipeline definition", + "description": "Update pipeline definition. Currently only supported for pipeline definitions where `config_source.provider` is `github_app` or `bitbucket_dc`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Pipeline Definition" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "pipeline_definition_id", + "description": "An opaque identifier of a pipeline definition.", + "example": "6cb29b00-8e02-4357-8bc0-313983bf1f46", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "example": "Some pipeline name", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "Some pipeline description", + "description": "The description of the pipeline definition." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app` is the only supported value." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline definition." + }, + "name": { + "type": "string", + "example": "some pipeline", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "some pipeline description", + "description": "The description of the pipeline definition." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline definition was created." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"name\\\": \\\"Some pipeline name\\\",\n \\\"description\\\": \\\"Some pipeline description\\\",\n \\\"config_source\\\": {\n \\\"file_path\\\": \\\".circleci/some-pipeline.yml\\\"\n }\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"name\":\"Some pipeline name\",\"description\":\"Some pipeline description\",\"config_source\":{\"file_path\":\".circleci/some-pipeline.yml\"}}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"name\\\": \\\"Some pipeline name\\\",\\n \\\"description\\\": \\\"Some pipeline description\\\",\\n \\\"config_source\\\": {\\n \\\"file_path\\\": \\\".circleci/some-pipeline.yml\\\"\\n }\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"name\\\": \\\"Some pipeline name\\\",\\n \\\"description\\\": \\\"Some pipeline description\\\",\\n \\\"config_source\\\": {\\n \\\"file_path\\\": \\\".circleci/some-pipeline.yml\\\"\\n }\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"name\\\": \\\"Some pipeline name\\\",\\n \\\"description\\\": \\\"Some pipeline description\\\",\\n \\\"config_source\\\": {\\n \\\"file_path\\\": \\\".circleci/some-pipeline.yml\\\"\\n }\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "operationId": "deletePipelineDefinition", + "summary": "Delete pipeline definition", + "description": "Delete pipeline definition. Currently only supported for pipeline definitions where `config_source.provider` is `github_app` or `bitbucket_dc`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Pipeline Definition" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "pipeline_definition_id", + "description": "An opaque identifier of a pipeline definition.", + "example": "6cb29b00-8e02-4357-8bc0-313983bf1f46", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "Response message" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers": { + "get": { + "operationId": "listPipelineDefinitionTriggers", + "summary": "List pipeline definition triggers", + "description": "List all triggers for a given pipeline definition. Currently only supported for pipeline definitions where `config_source.provider` is `github_app` or `bitbucket_dc`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Trigger" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "pipeline_definition_id", + "description": "An opaque identifier of a pipeline definition.", + "example": "6cb29b00-8e02-4357-8bc0-313983bf1f46", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the event that will trigger the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was created." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. Will contain either a `repo` or `webhook` object depending on the `provider`. (The `github_app` and `github_oauth` providers imply a `repo` and `webhook` implies a `webhook`.)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook used as a source of events for this trigger, if applicable.", + "properties": { + "url": { + "type": "string", + "example": "https://some-webhook.invalid/some-endpoint?secret=some-secret", + "description": "The URL to use when triggering this webhook." + }, + "sender": { + "type": "string", + "example": "datadog", + "description": "The name of the webhook sender.." + } + } + } + } + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger is disabled. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "post": { + "operationId": "createTrigger", + "summary": "Create trigger", + "description": "Create a trigger for a given pipeline definition. Currently only supported for pipeline definitions where `config_source.provider` is `github_app`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Trigger" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "pipeline_definition_id", + "description": "An opaque identifier of a pipeline definition.", + "example": "6cb29b00-8e02-4357-8bc0-313983bf1f46", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. The `repo` object must be specified when `provider` is `github_app`, and the `webhook` object may only be specified when `provider` is `webhook`.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + }, + "required": [ + "external_id" + ] + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook being used as a source of events for this trigger, if applicable.", + "properties": { + "sender": { + "type": "string", + "example": "some-webhook-sender", + "description": "The sender of the webhook." + } + } + } + }, + "required": [ + "provider" + ] + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. Always required when `event_source.provider` is `webhook`. When `event_source.provider` is `github_app`, only expected if the event source repository (identified by `event_source.provider.repo.external_id`) is different to the checkout source repository of the associated Pipeline Definition. Otherwise, must be omitted." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. Always required when `event_source.provider` is `webhook`. When `event_source.provider` is `github_app`, only expected if the event source repository (identified by `event_source.provider.repo.external_id`) is different to the config source repository of the associated Pipeline Definition. Otherwise, must be omitted." + }, + "event_name": { + "type": "string", + "example": "some-event-name", + "description": "The name of the triggering event. This should only be set for triggers where `provider` is `webhook`." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger should be disabled upon creation. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + }, + "required": [ + "event_source" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the event that will trigger the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was created." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. Will contain either a `repo` or `webhook` object depending on the `provider`. (The `github_app` and `github_oauth` providers imply a `repo` and `webhook` implies a `webhook`.)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook used as a source of events for this trigger, if applicable.", + "properties": { + "url": { + "type": "string", + "example": "https://some-webhook.invalid/some-endpoint?secret=some-secret", + "description": "The URL to use when triggering this webhook." + }, + "sender": { + "type": "string", + "example": "datadog", + "description": "The name of the webhook sender.." + } + } + } + } + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger is disabled. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"event_source\\\": {\n \\\"provider\\\": \\\"github_app\\\",\n \\\"repo\\\": {\n \\\"external_id\\\": \\\"some-repo-id\\\"\n },\n \\\"webhook\\\": {\n \\\"sender\\\": \\\"some-webhook-sender\\\"\n }\n },\n \\\"event_preset\\\": \\\"all-pushes\\\",\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"event_source\":{\"provider\":\"github_app\",\"repo\":{\"external_id\":\"some-repo-id\"},\"webhook\":{\"sender\":\"some-webhook-sender\"}},\"event_preset\":\"all-pushes\",\"checkout_ref\":\"some-checkout-ref\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"event_source\\\": {\\n \\\"provider\\\": \\\"github_app\\\",\\n \\\"repo\\\": {\\n \\\"external_id\\\": \\\"some-repo-id\\\"\\n },\\n \\\"webhook\\\": {\\n \\\"sender\\\": \\\"some-webhook-sender\\\"\\n }\\n },\\n \\\"event_preset\\\": \\\"all-pushes\\\",\\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"event_source\\\": {\\n \\\"provider\\\": \\\"github_app\\\",\\n \\\"repo\\\": {\\n \\\"external_id\\\": \\\"some-repo-id\\\"\\n },\\n \\\"webhook\\\": {\\n \\\"sender\\\": \\\"some-webhook-sender\\\"\\n }\\n },\\n \\\"event_preset\\\": \\\"all-pushes\\\",\\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/pipeline-definitions/6cb29b00-8e02-4357-8bc0-313983bf1f46/triggers\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"event_source\\\": {\\n \\\"provider\\\": \\\"github_app\\\",\\n \\\"repo\\\": {\\n \\\"external_id\\\": \\\"some-repo-id\\\"\\n },\\n \\\"webhook\\\": {\\n \\\"sender\\\": \\\"some-webhook-sender\\\"\\n }\\n },\\n \\\"event_preset\\\": \\\"all-pushes\\\",\\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/projects/{project_id}/triggers/{trigger_id}": { + "get": { + "operationId": "getTrigger", + "summary": "Get trigger", + "description": "Get details for a trigger. Currently only supported for triggers where `event_source.provider` is `github_app`, `bitbucket_dc` or `webhook`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs. Breaking change [upcoming on May 27, 2025](https://discuss.circleci.com/t/upcoming-changes-1-breaking-to-crud-trigger-v2-apis-may-27-2025/53314).", + "tags": [ + "Trigger" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "trigger_id", + "description": "An opaque identifier of a trigger.", + "example": "bbea3a3d-4686-48b6-8d2d-2a14ace3913c", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the event that will trigger the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was created." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. Will contain either a `repo` or `webhook` object depending on the `provider`. (The `github_app` and `github_oauth` providers imply a `repo` and `webhook` implies a `webhook`.)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook used as a source of events for this trigger, if applicable.", + "properties": { + "url": { + "type": "string", + "example": "https://some-webhook.invalid/some-endpoint?secret=some-secret", + "description": "The URL to use when triggering this webhook." + }, + "sender": { + "type": "string", + "example": "datadog", + "description": "The name of the webhook sender.." + } + } + } + } + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger is disabled. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "patch": { + "operationId": "updateTrigger", + "summary": "Update trigger", + "description": "Update a trigger. Currently only supported for triggers where `event_source.provider` is `github_app`, `bitbucket_dc` or `webhook`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Trigger" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "trigger_id", + "description": "An opaque identifier of a trigger.", + "example": "bbea3a3d-4686-48b6-8d2d-2a14ace3913c", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the triggering event. This can only be set for triggers where `provider` is `webhook`." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "A flag indicating whether the trigger is disabled or not. This can only be set for triggers where `provider` is `webhook`." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhook": { + "type": "object", + "additionalProperties": false, + "properties": { + "sender": { + "type": "string", + "example": "some sender", + "description": "The sender of the webhook. This can only be set for triggers where `provider` is `webhook`." + } + } + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the event that will trigger the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was created." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. Will contain either a `repo` or `webhook` object depending on the `provider`. (The `github_app` and `github_oauth` providers imply a `repo` and `webhook` implies a `webhook`.)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook used as a source of events for this trigger, if applicable.", + "properties": { + "url": { + "type": "string", + "example": "https://some-webhook.invalid/some-endpoint?secret=some-secret", + "description": "The URL to use when triggering this webhook." + }, + "sender": { + "type": "string", + "example": "datadog", + "description": "The name of the webhook sender.." + } + } + } + } + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger is disabled. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request PATCH \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"event_preset\\\": \\\"all-pushes\\\",\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\",\n \\\"config_ref\\\": \\\"some-config-ref\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c';\n const options = {\n method: 'PATCH',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"event_preset\":\"all-pushes\",\"checkout_ref\":\"some-checkout-ref\",\"config_ref\":\"some-config-ref\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"event_preset\\\": \\\"all-pushes\\\",\\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\",\\n \\\"config_ref\\\": \\\"some-config-ref\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"PATCH\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"event_preset\\\": \\\"all-pushes\\\",\\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\",\\n \\\"config_ref\\\": \\\"some-config-ref\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"PATCH\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Patch.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"event_preset\\\": \\\"all-pushes\\\",\\n \\\"checkout_ref\\\": \\\"some-checkout-ref\\\",\\n \\\"config_ref\\\": \\\"some-config-ref\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + }, + "delete": { + "operationId": "deleteTrigger", + "summary": "Delete trigger", + "description": "Delete a trigger. Currently only supported for triggers where `event_source.provider` is `github_app`, `bitbucket_dc` or `webhook`. [Share feedback](https://circleci.canny.io/cloud-feature-requests/p/project-administration-apis) about our Project Administration APIs.", + "tags": [ + "Trigger" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "trigger_id", + "description": "An opaque identifier of a trigger.", + "example": "bbea3a3d-4686-48b6-8d2d-2a14ace3913c", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "description": "Response message" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "401": { + "description": "Credentials provided are invalid.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "invalid_token": { + "summary": "Token is invalid.", + "value": { + "message": "Invalid token provided." + } + }, + "old_token": { + "summary": "Token was generated before 2023-06-23.", + "value": { + "message": "New format tokens are needed to authenticate this API endpoint. Create a new API token for access." + } + }, + "query_auth": { + "summary": "Authentication attempted via query parameters.", + "value": { + "message": "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request DELETE \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c';\n const options = {method: 'DELETE', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"DELETE\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/triggers/bbea3a3d-4686-48b6-8d2d-2a14ace3913c\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Delete.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/projects/{project_id}/rollback": { + "post": { + "operationId": "rollbackProject", + "summary": "Rollback a project", + "description": "Performs a rollback operation by triggering a rollback pipeline.", + "tags": [ + "Rollback" + ], + "parameters": [ + { + "name": "project_id", + "description": "An opaque identifier of a project.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "component_name": { + "description": "The component name", + "example": "frontend", + "type": "string", + "x-go-name": "ComponentName" + }, + "current_version": { + "description": "The current version", + "example": "1.0.0", + "type": "string", + "x-go-name": "CurrentVersion" + }, + "environment_name": { + "description": "The environment name", + "example": "production", + "type": "string", + "x-go-name": "EnvironmentName" + }, + "namespace": { + "description": "The namespace", + "example": "default", + "type": "string", + "x-go-name": "Namespace" + }, + "parameters": { + "additionalProperties": {}, + "description": "The extra parameters for the rollback pipeline", + "example": { + "param1": "value1", + "param2": "value2" + }, + "type": "object", + "x-go-name": "Parameters" + }, + "reason": { + "description": "The reason for the rollback", + "example": "The component is down", + "type": "string", + "x-go-name": "Reason" + }, + "target_version": { + "description": "The target version", + "example": "1.0.1", + "type": "string", + "x-go-name": "TargetVersion" + } + }, + "required": [ + "environment_name", + "component_name", + "current_version", + "target_version" + ] + } + } + }, + "required": true + }, + "responses": { + "202": { + "description": "Rollback request accepted.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "description": "The ID of the rollback pipeline or the command created to handle the rollback", + "example": "123e4567-e89b-12d3-a456-426614174000", + "format": "uuid", + "type": "string" + }, + "rollback_type": { + "description": "The type of the rollback", + "example": "PIPELINE", + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "409": { + "description": "A conflict has occurred while attempting to create the resource.\n", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Conflict creating entity." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request POST \\\n --url https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/rollback \\\n --header \"Circle-Token: $CIRCLE_TOKEN\" \\\n --header \"Content-Type: application/json\" \\\n --data \"{\n \\\"component_name\\\": \\\"frontend\\\",\n \\\"current_version\\\": \\\"1.0.0\\\",\n \\\"environment_name\\\": \\\"production\\\",\n \\\"target_version\\\": \\\"1.0.1\\\"\n}\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/rollback';\n const options = {\n method: 'POST',\n headers: {'Circle-Token': '$CIRCLE_TOKEN', 'Content-Type': 'application/json'},\n body: '{\"component_name\":\"frontend\",\"current_version\":\"1.0.0\",\"environment_name\":\"production\",\"target_version\":\"1.0.1\"}'\n };\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\npayload = \"{\\n \\\"component_name\\\": \\\"frontend\\\",\\n \\\"current_version\\\": \\\"1.0.0\\\",\\n \\\"environment_name\\\": \\\"production\\\",\\n \\\"target_version\\\": \\\"1.0.1\\\"\\n}\"\n\nheaders = {\n 'Circle-Token': \"$CIRCLE_TOKEN\",\n 'Content-Type': \"application/json\"\n}\n\nconn.request(\"POST\", \"/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/rollback\", payload, headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/rollback\"\n\n\tpayload := strings.NewReader(\"{\\n \\\"component_name\\\": \\\"frontend\\\",\\n \\\"current_version\\\": \\\"1.0.0\\\",\\n \\\"environment_name\\\": \\\"production\\\",\\n \\\"target_version\\\": \\\"1.0.1\\\"\\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/projects/39723015-b399-4601-9ff6-bd1bfbed8fa8/rollback\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Post.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\nrequest[\"Content-Type\"] = 'application/json'\nrequest.body = \"{\\n \\\"component_name\\\": \\\"frontend\\\",\\n \\\"current_version\\\": \\\"1.0.0\\\",\\n \\\"environment_name\\\": \\\"production\\\",\\n \\\"target_version\\\": \\\"1.0.1\\\"\\n}\"\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/deploy/environments": { + "get": { + "operationId": "listEnvironments", + "summary": "List Environments", + "description": "Allows listing environments for a given organization ID.", + "tags": [ + "Deploy" + ], + "parameters": [ + { + "name": "org-id", + "description": "An opaque identifier of an organization used in query parameters.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page-size", + "in": "query", + "required": true, + "description": "The number of results per page.", + "schema": { + "type": "integer" + } + }, + { + "name": "page-token", + "in": "query", + "description": "A token to specify which page of results to fetch.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Paginated environments list", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "created_at": { + "description": "The time when the environment was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "description": { + "description": "Short description given to the environment", + "example": "some description", + "type": "string", + "x-go-name": "Description" + }, + "id": { + "description": "The environment ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated to the environment", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "name": { + "description": "The environment name", + "example": "prod-app", + "type": "string", + "x-go-name": "Name" + }, + "updated_at": { + "description": "The time when the environment was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + }, + "type": "array", + "x-go-name": "Items" + }, + "next_page_token": { + "description": "The pagination token to use when fetching the next page in this result set.", + "type": "string", + "nullable": true, + "x-go-name": "NextPageToken" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/deploy/environments?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&page-size=123&page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/deploy/environments?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&page-size=123&page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/deploy/environments?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&page-size=123&page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/deploy/environments?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&page-size=123&page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/deploy/environments?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&page-size=123&page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/deploy/environments/{environment_id}": { + "get": { + "operationId": "getEnvironment", + "summary": "Get Environment", + "description": "Allows getting an environment for a given environment ID.", + "tags": [ + "Deploy" + ], + "parameters": [ + { + "name": "environment_id", + "description": "An opaque identifier of an environment.", + "example": "1c23d2cb-07b1-4a28-8af3-e369732050ed", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Environment", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "created_at": { + "description": "The time when the environment was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "description": { + "description": "Short description given to the environment", + "example": "some description", + "type": "string", + "x-go-name": "Description" + }, + "id": { + "description": "The environment ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated to the environment", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "name": { + "description": "The environment name", + "example": "prod-app", + "type": "string", + "x-go-name": "Name" + }, + "updated_at": { + "description": "The time when the environment was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/deploy/environments/1c23d2cb-07b1-4a28-8af3-e369732050ed \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/deploy/environments/1c23d2cb-07b1-4a28-8af3-e369732050ed';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/deploy/environments/1c23d2cb-07b1-4a28-8af3-e369732050ed\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/deploy/environments/1c23d2cb-07b1-4a28-8af3-e369732050ed\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/deploy/environments/1c23d2cb-07b1-4a28-8af3-e369732050ed\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/deploy/components": { + "get": { + "operationId": "listComponents", + "summary": "List Components", + "description": "Allows for listing of components for a given organization ID.", + "tags": [ + "Deploy" + ], + "parameters": [ + { + "name": "org-id", + "description": "An opaque identifier of an organization used in query parameters.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "project-id", + "description": "An opaque identifier of an project used in query parameters.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page-size", + "in": "query", + "required": true, + "description": "The number of results per page.", + "schema": { + "type": "integer" + } + }, + { + "name": "page-token", + "in": "query", + "description": "A token to specify which page of results to fetch.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Paginated components list", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "description": "The component ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "name": { + "description": "The component name", + "example": "service-a", + "type": "string", + "x-go-name": "Name" + }, + "project_id": { + "description": "The project ID of the component", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated with the component", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "release_count": { + "description": "The number of releases for this component", + "example": 1, + "type": "integer", + "x-go-name": "ReleaseCount" + }, + "created_at": { + "description": "The time when the component was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "updated_at": { + "description": "The time when the component was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + }, + "type": "array", + "x-go-name": "Items" + }, + "next_page_token": { + "description": "The pagination token to use when fetching the next page in this result set.", + "type": "string", + "nullable": true, + "x-go-name": "NextPageToken" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/deploy/components?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&project-id=39723015-b399-4601-9ff6-bd1bfbed8fa8&page-size=123&page-token=example-value\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/deploy/components?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&project-id=39723015-b399-4601-9ff6-bd1bfbed8fa8&page-size=123&page-token=example-value';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/deploy/components?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&project-id=39723015-b399-4601-9ff6-bd1bfbed8fa8&page-size=123&page-token=example-value\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/deploy/components?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&project-id=39723015-b399-4601-9ff6-bd1bfbed8fa8&page-size=123&page-token=example-value\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/deploy/components?org-id=b9291e0d-a11e-41fb-8517-c545388b5953&project-id=39723015-b399-4601-9ff6-bd1bfbed8fa8&page-size=123&page-token=example-value\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/deploy/components/{component_id}": { + "get": { + "operationId": "getComponent", + "summary": "Get Component", + "description": "Get the details of a component by ID.", + "tags": [ + "Deploy" + ], + "parameters": [ + { + "name": "component_id", + "description": "An opaque identifier of a component.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful response.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "description": "The component ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "name": { + "description": "The component name", + "example": "service-a", + "type": "string", + "x-go-name": "Name" + }, + "project_id": { + "description": "The project ID of the component", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated with the component", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "release_count": { + "description": "The number of releases for this component", + "example": 1, + "type": "integer", + "x-go-name": "ReleaseCount" + }, + "created_at": { + "description": "The time when the component was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "updated_at": { + "description": "The time when the component was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953 \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + }, + "/deploy/components/{component_id}/versions": { + "get": { + "operationId": "listComponentVersions", + "summary": "List Component Versions", + "description": "List the versions for a component.", + "tags": [ + "Deploy" + ], + "parameters": [ + { + "name": "component_id", + "description": "An opaque identifier of a component.", + "example": "b9291e0d-a11e-41fb-8517-c545388b5953", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "environment-id", + "description": "An opaque identifier of an environment used in query parameters.", + "example": "39723015-b399-4601-9ff6-bd1bfbed8fa8", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Paginated component versions list", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "The version name", + "example": "1.0.0", + "type": "string", + "x-go-name": "Name" + }, + "environment_id": { + "description": "The ID of the environment in which the version has been deployed", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "namespace": { + "description": "The namespace in which the version was deployed", + "example": "default", + "type": "string", + "x-go-name": "Namespace" + }, + "is_live": { + "description": "Whether the version is live or not", + "example": true, + "type": "boolean", + "x-go-name": "IsLive" + }, + "pipeline_id": { + "description": "The ID of the pipeline that deployed the version", + "example": "cc54a110-d03f-4916-96fc-ff36a1221ed7", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "workflow_id": { + "description": "The ID of the CircleCI workflow that deployed the version", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "format": "uuid", + "type": "string", + "x-go-name": "WorkflowID" + }, + "job_id": { + "description": "The ID of the CircleCI job that deployed the version", + "example": "f7e18b53-db27-4706-ad77-b16dc1e6fc53", + "format": "uuid", + "type": "string", + "x-go-name": "JobID" + }, + "job_number": { + "description": "The number of the CircleCI job that deployed the version", + "example": 123, + "type": "integer", + "x-go-name": "JobNumber" + }, + "last_deployed_at": { + "description": "The time at which the version was last deployed", + "format": "date-time", + "type": "string", + "x-go-name": "LastDeployedAt" + } + } + }, + "type": "array", + "x-go-name": "Items" + }, + "next_page_token": { + "description": "The pagination token to use when fetching the next page in this result set.", + "type": "string", + "nullable": true, + "x-go-name": "NextPageToken" + } + } + } + } + } + }, + "400": { + "description": "Unexpected request body provided.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Unexpected request body provided." + } + } + } + } + } + }, + "404": { + "description": "Entity not found.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + } + } + }, + "examples": { + "context_not_found": { + "summary": "Context not found.", + "value": { + "message": "Context not found." + } + }, + "org_not_found": { + "summary": "Organization not found.", + "value": { + "message": "Organization does not exist." + } + }, + "user_not_found": { + "summary": "User not found.", + "value": { + "message": "User does not exist." + } + }, + "project_not_found": { + "summary": "Project not found.", + "value": { + "message": "Project does not exist." + } + }, + "group_not_found": { + "summary": "Group not found.", + "value": { + "message": "Group does not exist." + } + }, + "orb_not_found": { + "summary": "Orb not found.", + "value": { + "message": "Orb does not exist." + } + } + } + } + } + }, + "500": { + "description": "Internal server error.", + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "default": "Internal server error." + } + } + } + } + } + } + }, + "x-code-samples": [ + { + "lang": "cURL", + "source": "curl --request GET \\\n --url \"https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953/versions?environment-id=39723015-b399-4601-9ff6-bd1bfbed8fa8\" \\\n --header \"Circle-Token: $CIRCLE_TOKEN\"" + }, + { + "lang": "Node.js", + "source": "const fetch = require('node-fetch');\n\nasync function run() {\n const url = 'https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953/versions?environment-id=39723015-b399-4601-9ff6-bd1bfbed8fa8';\n const options = {method: 'GET', headers: {'Circle-Token': '$CIRCLE_TOKEN'}};\n try {\n const response = await fetch(url, options);\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(error);\n }\n}\n\nrun();" + }, + { + "lang": "Python", + "source": "import http.client\n\nconn = http.client.HTTPSConnection(\"circleci.com\")\n\nheaders = { 'Circle-Token': \"$CIRCLE_TOKEN\" }\n\nconn.request(\"GET\", \"/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953/versions?environment-id=39723015-b399-4601-9ff6-bd1bfbed8fa8\", headers=headers)\n\nres = conn.getresponse()\ndata = res.read()\n\nprint(data.decode(\"utf-8\"))" + }, + { + "lang": "Go", + "source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io\"\n)\n\nfunc main() {\n\n\turl := \"https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953/versions?environment-id=39723015-b399-4601-9ff6-bd1bfbed8fa8\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Circle-Token\", \"$CIRCLE_TOKEN\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := io.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" + }, + { + "lang": "Ruby", + "source": "require 'uri'\nrequire 'net/http'\n\nurl = URI(\"https://circleci.com/api/v2/deploy/components/b9291e0d-a11e-41fb-8517-c545388b5953/versions?environment-id=39723015-b399-4601-9ff6-bd1bfbed8fa8\")\n\nhttp = Net::HTTP.new(url.host, url.port)\nhttp.use_ssl = true\n\nrequest = Net::HTTP::Get.new(url)\nrequest[\"Circle-Token\"] = '$CIRCLE_TOKEN'\n\nresponse = http.request(request)\nputs response.read_body" + } + ] + } + } + }, + "components": { + "securitySchemes": { + "api_key_header": { + "type": "apiKey", + "name": "Circle-Token", + "in": "header", + "description": "Project API tokens are not supported for API v2. Use a personal API token." + }, + "basic_auth": { + "description": "HTTP basic authentication. The username should be set as the circle-token value, and the password should be left blank. Note that project tokens are currently not supported on API v2.", + "type": "http", + "scheme": "basic" + }, + "api_key_query": { + "type": "apiKey", + "name": "circle-token", + "in": "query", + "description": "DEPRECATED - we will remove this option in the future. Project API tokens are not supported for API v2. Use a personal API token." + } + }, + "schemas": { + "ClaimResponse": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "audience_updated_at": { + "format": "date-time", + "type": "string" + }, + "org_id": { + "format": "uuid", + "type": "string" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + }, + "ttl_updated_at": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "org_id" + ], + "type": "object" + }, + "PatchClaimsRequest": { + "properties": { + "audience": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ttl": { + "pattern": "^([0-9]+(ms|s|m|h|d|w)){1,7}$", + "type": "string" + } + }, + "type": "object" + }, + "Decision": { + "properties": { + "enabled_rules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "hard_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "reason": { + "type": "string" + }, + "soft_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "DecisionLog": { + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "decision": { + "properties": { + "enabled_rules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "hard_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "reason": { + "type": "string" + }, + "soft_failures": { + "items": { + "properties": { + "reason": { + "type": "string" + }, + "rule": { + "type": "string" + } + }, + "required": [ + "rule", + "reason" + ], + "type": "object" + }, + "type": "array" + }, + "status": { + "type": "string" + } + }, + "required": [ + "status" + ], + "type": "object" + }, + "id": { + "format": "uuid", + "type": "string" + }, + "metadata": { + "properties": { + "build_number": { + "type": "integer" + }, + "project_id": { + "format": "uuid", + "type": "string" + }, + "ssh_rerun": { + "type": "boolean" + }, + "vcs": { + "properties": { + "branch": { + "type": "string" + }, + "origin_repository_url": { + "type": "string" + }, + "release_tag": { + "type": "string" + }, + "target_repository_url": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "policies": { + "additionalProperties": { + "maxLength": 128, + "minLength": 128, + "type": "string" + }, + "description": "policy-name-to-hash-map", + "example": { + "policy_name1": "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + "policy_name2": "5267768822ee624d48fce15ec5ca79cbd602cb7f4c2157a516556991f22ef8c7b5ef7b18d1ff41c59370efb0858651d44a936c11b7b144c48fe04df3c6a3e8da" + }, + "type": "object" + }, + "time_taken_ms": { + "type": "integer" + } + }, + "type": "object" + }, + "PolicyBundle": { + "additionalProperties": { + "items": { + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "format": "date-time", + "type": "string" + }, + "created_by": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "groups": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for group" + }, + "name": { + "type": "string", + "description": "Name of group" + }, + "description": { + "type": "string", + "description": "Description field on group" + } + } + } + }, + "next_page_token": { + "type": "string", + "nullable": true + }, + "total_count": { + "type": "integer" + } + } + }, + "pipelineDefinition": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline definition." + }, + "name": { + "type": "string", + "example": "some pipeline", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "some pipeline description", + "description": "The description of the pipeline definition." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline definition was created." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + }, + "pipelineDefinitionList": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the pipeline definition." + }, + "name": { + "type": "string", + "example": "some pipeline", + "description": "The name of the pipeline definition." + }, + "description": { + "type": "string", + "example": "some pipeline description", + "description": "The description of the pipeline definition." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the pipeline definition was created." + }, + "config_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource that stores the CircleCI config YAML used for this pipeline definition.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "file_path": { + "type": "string", + "example": ".circleci/some-pipeline.yml", + "description": "Path to CircleCI config YAML file to use for this pipeline definition." + } + } + }, + "checkout_source": { + "type": "object", + "additionalProperties": false, + "description": "The resource to be used when running the `checkout` command.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + } + } + } + } + } + } + } + }, + "trigger": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the event that will trigger the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was created." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. Will contain either a `repo` or `webhook` object depending on the `provider`. (The `github_app` and `github_oauth` providers imply a `repo` and `webhook` implies a `webhook`.)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook used as a source of events for this trigger, if applicable.", + "properties": { + "url": { + "type": "string", + "example": "https://some-webhook.invalid/some-endpoint?secret=some-secret", + "description": "The URL to use when triggering this webhook." + }, + "sender": { + "type": "string", + "example": "datadog", + "description": "The name of the webhook sender.." + } + } + } + } + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger is disabled. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + } + }, + "triggerList": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique ID of the trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the event that will trigger the pipeline." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The date and time the trigger was created." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. Will contain either a `repo` or `webhook` object depending on the `provider`. (The `github_app` and `github_oauth` providers imply a `repo` and `webhook` implies a `webhook`.)", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "full_name": { + "type": "string", + "example": "some-org/some-repo-name", + "description": "The fully-qualified name of the repository." + }, + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + } + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook used as a source of events for this trigger, if applicable.", + "properties": { + "url": { + "type": "string", + "example": "https://some-webhook.invalid/some-endpoint?secret=some-secret", + "description": "The URL to use when triggering this webhook." + }, + "sender": { + "type": "string", + "example": "datadog", + "description": "The name of the webhook sender.." + } + } + } + } + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. If empty, the ref provided in the trigger event is used." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger is disabled. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + } + } + } + } + }, + "createTriggerRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_source": { + "type": "object", + "additionalProperties": false, + "description": "The source of events to use for this trigger. The `repo` object must be specified when `provider` is `github_app`, and the `webhook` object may only be specified when `provider` is `webhook`.", + "properties": { + "provider": { + "type": "string", + "example": "github_app", + "description": "The integration provider for this resource. Currently `github_app`, `github_oauth`, and `webhook` are the only supported values." + }, + "repo": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the repository used as a source of events for this trigger, if applicable.", + "properties": { + "external_id": { + "type": "string", + "example": "some-repo-id", + "description": "External identifier for the repository, as defined by the respective version control provider." + } + }, + "required": [ + "external_id" + ] + }, + "webhook": { + "type": "object", + "additionalProperties": false, + "description": "Information pertaining to the custom webhook being used as a source of events for this trigger, if applicable.", + "properties": { + "sender": { + "type": "string", + "example": "some-webhook-sender", + "description": "The sender of the webhook." + } + } + } + }, + "required": [ + "provider" + ] + }, + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger. Always required when `event_source.provider` is `webhook`. When `event_source.provider` is `github_app`, only expected if the event source repository (identified by `event_source.provider.repo.external_id`) is different to the checkout source repository of the associated Pipeline Definition. Otherwise, must be omitted." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger. Always required when `event_source.provider` is `webhook`. When `event_source.provider` is `github_app`, only expected if the event source repository (identified by `event_source.provider.repo.external_id`) is different to the config source repository of the associated Pipeline Definition. Otherwise, must be omitted." + }, + "event_name": { + "type": "string", + "example": "some-event-name", + "description": "The name of the triggering event. This should only be set for triggers where `provider` is `webhook`." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "Whether the trigger should be disabled upon creation. Not supported for pipeline definitions where `config_source.provider` is `github_oauth`." + } + }, + "required": [ + "event_source" + ] + }, + "updateTriggerRequest": { + "type": "object", + "additionalProperties": false, + "properties": { + "event_preset": { + "type": "string", + "example": "all-pushes", + "description": "The name of the event preset to use when filtering events for this trigger. Only applicable when `event_source.provider` is `github_app`." + }, + "checkout_ref": { + "type": "string", + "example": "some-checkout-ref", + "description": "The ref to use when checking out code for pipeline runs created from this trigger." + }, + "config_ref": { + "type": "string", + "example": "some-config-ref", + "description": "The ref to use when fetching config for pipeline runs created from this trigger." + }, + "event_name": { + "type": "string", + "example": "some event name", + "description": "The name of the triggering event. This can only be set for triggers where `provider` is `webhook`." + }, + "disabled": { + "type": "boolean", + "example": false, + "description": "A flag indicating whether the trigger is disabled or not. This can only be set for triggers where `provider` is `webhook`." + }, + "event_source": { + "type": "object", + "additionalProperties": false, + "properties": { + "webhook": { + "type": "object", + "additionalProperties": false, + "properties": { + "sender": { + "type": "string", + "example": "some sender", + "description": "The sender of the webhook. This can only be set for triggers where `provider` is `webhook`." + } + } + } + } + } + } + }, + "component": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "description": "The component ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "name": { + "description": "The component name", + "example": "service-a", + "type": "string", + "x-go-name": "Name" + }, + "project_id": { + "description": "The project ID of the component", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated with the component", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "release_count": { + "description": "The number of releases for this component", + "example": 1, + "type": "integer", + "x-go-name": "ReleaseCount" + }, + "created_at": { + "description": "The time when the component was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "updated_at": { + "description": "The time when the component was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + }, + "paginatedComponentList": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "description": "The component ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "name": { + "description": "The component name", + "example": "service-a", + "type": "string", + "x-go-name": "Name" + }, + "project_id": { + "description": "The project ID of the component", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated with the component", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "release_count": { + "description": "The number of releases for this component", + "example": 1, + "type": "integer", + "x-go-name": "ReleaseCount" + }, + "created_at": { + "description": "The time when the component was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "updated_at": { + "description": "The time when the component was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + }, + "type": "array", + "x-go-name": "Items" + }, + "next_page_token": { + "description": "The pagination token to use when fetching the next page in this result set.", + "type": "string", + "nullable": true, + "x-go-name": "NextPageToken" + } + } + }, + "paginatedComponentVersionList": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "The version name", + "example": "1.0.0", + "type": "string", + "x-go-name": "Name" + }, + "environment_id": { + "description": "The ID of the environment in which the version has been deployed", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "namespace": { + "description": "The namespace in which the version was deployed", + "example": "default", + "type": "string", + "x-go-name": "Namespace" + }, + "is_live": { + "description": "Whether the version is live or not", + "example": true, + "type": "boolean", + "x-go-name": "IsLive" + }, + "pipeline_id": { + "description": "The ID of the pipeline that deployed the version", + "example": "cc54a110-d03f-4916-96fc-ff36a1221ed7", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "workflow_id": { + "description": "The ID of the CircleCI workflow that deployed the version", + "example": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "format": "uuid", + "type": "string", + "x-go-name": "WorkflowID" + }, + "job_id": { + "description": "The ID of the CircleCI job that deployed the version", + "example": "f7e18b53-db27-4706-ad77-b16dc1e6fc53", + "format": "uuid", + "type": "string", + "x-go-name": "JobID" + }, + "job_number": { + "description": "The number of the CircleCI job that deployed the version", + "example": 123, + "type": "integer", + "x-go-name": "JobNumber" + }, + "last_deployed_at": { + "description": "The time at which the version was last deployed", + "format": "date-time", + "type": "string", + "x-go-name": "LastDeployedAt" + } + } + }, + "type": "array", + "x-go-name": "Items" + }, + "next_page_token": { + "description": "The pagination token to use when fetching the next page in this result set.", + "type": "string", + "nullable": true, + "x-go-name": "NextPageToken" + } + } + }, + "environment": { + "type": "object", + "additionalProperties": false, + "properties": { + "created_at": { + "description": "The time when the environment was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "description": { + "description": "Short description given to the environment", + "example": "some description", + "type": "string", + "x-go-name": "Description" + }, + "id": { + "description": "The environment ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated to the environment", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "name": { + "description": "The environment name", + "example": "prod-app", + "type": "string", + "x-go-name": "Name" + }, + "updated_at": { + "description": "The time when the environment was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + }, + "paginatedEnvironmentList": { + "type": "object", + "additionalProperties": false, + "properties": { + "items": { + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "created_at": { + "description": "The time when the environment was created", + "format": "date-time", + "type": "string", + "x-go-name": "CreatedAt" + }, + "description": { + "description": "Short description given to the environment", + "example": "some description", + "type": "string", + "x-go-name": "Description" + }, + "id": { + "description": "The environment ID", + "example": "123e4127-e89b-12d3-a456-426123417400", + "format": "uuid", + "type": "string", + "x-go-name": "ID" + }, + "labels": { + "description": "The labels associated to the environment", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "description": "The key of the label", + "example": "env", + "type": "string", + "x-go-name": "Key" + }, + "value": { + "description": "The value of the label", + "example": "prod", + "type": "string", + "x-go-name": "Value" + } + } + }, + "type": "array", + "x-go-name": "Labels" + }, + "name": { + "description": "The environment name", + "example": "prod-app", + "type": "string", + "x-go-name": "Name" + }, + "updated_at": { + "description": "The time when the environment was updated", + "format": "date-time", + "type": "string", + "x-go-name": "UpdatedAt" + } + } + }, + "type": "array", + "x-go-name": "Items" + }, + "next_page_token": { + "description": "The pagination token to use when fetching the next page in this result set.", + "type": "string", + "nullable": true, + "x-go-name": "NextPageToken" + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/CIRCLECI_API/config.yml b/tests/CIRCLECI_API/config.yml new file mode 100644 index 00000000..1bb26040 --- /dev/null +++ b/tests/CIRCLECI_API/config.yml @@ -0,0 +1,55 @@ + +# This config.yml contains user provided data for api testing. Allows to define values here or use ENV to load values. e.g. ENV[API_HOST] = "https://exampl2.com" +# api: +# host: "${API_HOST:-https://example.com/api/v2}" # includes base path +# auth: +# api_key: "${API_KEY:-}" +# api_key_header: "${KEYNAME:-DefaultValue}" # openapi.spec.security.KEY_NAME +# basic_auth: "${username:-}:${password:-}" +# test_data: +# id: "${TEST_ID:-282739-1238371-219393-2833}" # Any test data key value pair e.g. GET /api/v1/cart/:id +# context-id: "${TEST_context-id:-}" # GET /api/v1/{context-id}/summary + + + +api: + host: "${API_HOST:-https://circleci.com/api/v2}" +auth: + api_key_header: "${Circle-Token:-}" + api_key_query: "${circle-token:-}" +test_data: + project-slug: "${TEST_project-slug:-}" + workflow-name: "${TEST_workflow-name:-}" + org-slug: "${TEST_org-slug:-}" + job-id: "${TEST_job-id:-}" + org-slug-or-id: "${TEST_org-slug-or-id:-}" + allow-list-entry-id: "${TEST_allow-list-entry-id:-}" + pipeline-id: "${TEST_pipeline-id:-}" + fingerprint: "${TEST_fingerprint:-}" + name: "${TEST_name:-}" + job-number: "${TEST_job-number:-}" + pipeline-number: "${TEST_pipeline-number:-}" + schedule-id: "${TEST_schedule-id:-}" + id: "${TEST_id:-}" + webhook-id: "${TEST_webhook-id:-}" + approval_request_id: "${TEST_approval_request_id:-}" + orgID: "${TEST_orgID:-}" + projectID: "${TEST_projectID:-}" + ownerID: "${TEST_ownerID:-}" + context: "${TEST_context:-}" + decisionID: "${TEST_decisionID:-}" + policyName: "${TEST_policyName:-}" + context_id: "${TEST_context_id:-}" + env_var_name: "${TEST_env_var_name:-}" + restriction_id: "${TEST_restriction_id:-}" + provider: "${TEST_provider:-}" + organization: "${TEST_organization:-}" + project: "${TEST_project:-}" + org_id: "${TEST_org_id:-}" + group_id: "${TEST_group_id:-}" + usage_export_job_id: "${TEST_usage_export_job_id:-}" + project_id: "${TEST_project_id:-}" + pipeline_definition_id: "${TEST_pipeline_definition_id:-}" + trigger_id: "${TEST_trigger_id:-}" + environment_id: "${TEST_environment_id:-}" + component_id: "${TEST_component_id:-}" diff --git a/tests/CIRCLECI_API/conftest.py b/tests/CIRCLECI_API/conftest.py new file mode 100644 index 00000000..8211e9f1 --- /dev/null +++ b/tests/CIRCLECI_API/conftest.py @@ -0,0 +1,84 @@ +import os +import re +import pytest +import requests +import yaml +from pathlib import Path +from requests.adapters import HTTPAdapter +from requests.packages.urllib3.util.retry import Retry + +def _expand_env_in_string(value): + pattern = r'\${([^}:]+):-([^}]+)}' + def replacer(match): + env_var, default = match.groups() + return os.getenv(env_var, default) + return re.sub(pattern, replacer, value) + +def load_config(): + config_path = Path(__file__).parent / 'config.yml' + try: + with open(config_path, 'r') as file: + config = yaml.safe_load(file) + return {key: _expand_env_in_string(value) if isinstance(value, str) else value + for key, value in config.items()} + except FileNotFoundError: + raise RuntimeError(f"Configuration file not found at {config_path}") + except yaml.YAMLError as e: + raise RuntimeError(f"Error parsing YAML file: {e}") + +@pytest.fixture(scope='session') +def config(): + return load_config() + +@pytest.fixture(scope='session') +def api_host(config): + return config['api']['host'].strip() + +@pytest.fixture(scope='session') +def api_auth(config): + return { + 'api_key_header': config['auth']['api_key_header'], + 'api_key_query': config['auth']['api_key_query'] + } + +@pytest.fixture(scope='session') +def config_test_data(config): + return config['test_data'] + +class APIClient: + def __init__(self, host, auth): + self.host = host + self.auth = auth + self.session = requests.Session() + retries = Retry(total=3, backoff_factor=1, status_forcelist=[502, 503, 504]) + self.session.mount('https://', HTTPAdapter(max_retries=retries)) + + def make_request(self, endpoint, method='GET', headers=None, **kwargs): + url = f"{self.host}/{endpoint.lstrip('/')}" + headers = headers or {} + headers.update({'Authorization': f"Bearer {self.auth['api_key_header']}"}) + response = self.session.request(method, url, headers=headers, **kwargs) + response.raise_for_status() + return response + + def get(self, endpoint, **kwargs): + return self.make_request(endpoint, 'GET', **kwargs) + + def post(self, endpoint, **kwargs): + return self.make_request(endpoint, 'POST', **kwargs) + + def put(self, endpoint, **kwargs): + return self.make_request(endpoint, 'PUT', **kwargs) + + def delete(self, endpoint, **kwargs): + return self.make_request(endpoint, 'DELETE', **kwargs) + + def patch(self, endpoint, **kwargs): + return self.make_request(endpoint, 'PATCH', **kwargs) + +@pytest.fixture(scope='session') +def api_client(api_host, api_auth): + return APIClient(api_host, api_auth) + +def pytest_configure(config): + config.addinivalue_line("markers", "smoke: mark test as smoke test") diff --git a/tests/CIRCLECI_API/context.json b/tests/CIRCLECI_API/context.json new file mode 100644 index 00000000..a371b8fa --- /dev/null +++ b/tests/CIRCLECI_API/context.json @@ -0,0 +1,50 @@ +[ + { + "owner-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "owner-id": "123e4567-e89b-12d3-a456-426614174000", + "owner-slug": "valid-slug", + "owner-type": "organization", + "page-token": "token123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "owner-slug": "valid-slug", + "owner-type": "organization", + "page-token": "token123", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "owner-id": "invalid-uuid", + "owner-slug": "valid-slug", + "owner-type": "organization", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "owner-id": "123e4567-e89b-12d3-a456-426614174000", + "owner-slug": "nonexistent-slug", + "owner-type": "organization", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "owner-id": "123e4567-e89b-12d3-a456-426614174000", + "owner-slug": "valid-slug", + "owner-type": "organization", + "statusCode": 429, + "scenario": "Client error responses: Too Many Requests" + }, + { + "owner-id": "123e4567-e89b-12d3-a456-426614174000", + "owner-slug": "valid-slug", + "owner-type": "organization", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/context_context_id.json b/tests/CIRCLECI_API/context_context_id.json new file mode 100644 index 00000000..b57ab263 --- /dev/null +++ b/tests/CIRCLECI_API/context_context_id.json @@ -0,0 +1,37 @@ +[ + { + "context_id": "validContext123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "context_id": "validContext123", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "context_id": "nonExistentContext", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "context_id": "validContext123", + "statusCode": 429, + "scenario": "Client error responses: Too Many Requests" + }, + { + "context_id": "validContext123", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + }, + { + "context_id": "", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "context_id": "invalidContext!@#", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/context_context_id_environment-variable.json b/tests/CIRCLECI_API/context_context_id_environment-variable.json new file mode 100644 index 00000000..b2414b93 --- /dev/null +++ b/tests/CIRCLECI_API/context_context_id_environment-variable.json @@ -0,0 +1,38 @@ +[ + { + "context_id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "context_id": "123e4567-e89b-12d3-a456-426614174000", + "page-token": "abc123token", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-token": "abc123token", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "context_id": "invalid-uuid", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "context_id": "00000000-0000-0000-0000-000000000000", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "context_id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 429, + "scenario": "Client error responses: Too Many Requests" + }, + { + "context_id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/context_context_id_environment-variable_env_var_na.json b/tests/CIRCLECI_API/context_context_id_environment-variable_env_var_na.json new file mode 100644 index 00000000..cc7aacc7 --- /dev/null +++ b/tests/CIRCLECI_API/context_context_id_environment-variable_env_var_na.json @@ -0,0 +1,38 @@ +[ + { + "context_id": "validContext123", + "env_var_name": "validEnvVar", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "context_id": "validContext123", + "env_var_name": "validEnvVar", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "context_id": "nonExistentContext", + "env_var_name": "validEnvVar", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "context_id": "validContext123", + "env_var_name": "nonExistentEnvVar", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "context_id": "validContext123", + "env_var_name": "validEnvVar", + "statusCode": 429, + "scenario": "Client error responses: Too Many Requests" + }, + { + "context_id": "validContext123", + "env_var_name": "validEnvVar", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/context_context_id_restrictions.json b/tests/CIRCLECI_API/context_context_id_restrictions.json new file mode 100644 index 00000000..4e62e8fd --- /dev/null +++ b/tests/CIRCLECI_API/context_context_id_restrictions.json @@ -0,0 +1,31 @@ +[ + { + "restriction_type": "project", + "restriction_value": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "restriction_type": "project", + "restriction_value": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "restriction_type": "project", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "restriction_type": "invalid_type", + "restriction_value": "invalid_value", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "restriction_type": "project", + "restriction_value": "non-existent-id", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/context_context_id_restrictions_restriction_id.json b/tests/CIRCLECI_API/context_context_id_restrictions_restriction_id.json new file mode 100644 index 00000000..61cff50e --- /dev/null +++ b/tests/CIRCLECI_API/context_context_id_restrictions_restriction_id.json @@ -0,0 +1,32 @@ +[ + { + "message": "Operation completed successfully.", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "message": "restriction_id is invalid.", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "message": "Invalid credentials provided.", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "message": "The specified context_id or restriction_id was not found.", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "message": "Rate limit exceeded.", + "statusCode": 429, + "scenario": "Client error responses: Too Many Requests" + }, + { + "message": "Internal server error.", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/deploy_components.json b/tests/CIRCLECI_API/deploy_components.json new file mode 100644 index 00000000..17378dd5 --- /dev/null +++ b/tests/CIRCLECI_API/deploy_components.json @@ -0,0 +1,47 @@ +[ + { + "org-id": "123e4567-e89b-12d3-a456-426614174000", + "project-id": "123e4567-e89b-12d3-a456-426614174001", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-id": "123e4567-e89b-12d3-a456-426614174000", + "project-id": "123e4567-e89b-12d3-a456-426614174001", + "page-size": 10, + "page-token": "abc123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-id": "123e4567-e89b-12d3-a456-426614174000", + "page-size": 10, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "org-id": "invalid-uuid", + "project-id": "123e4567-e89b-12d3-a456-426614174001", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "org-id": "123e4567-e89b-12d3-a456-426614174000", + "project-id": "non-existent-project-id", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "org-id": "123e4567-e89b-12d3-a456-426614174000", + "project-id": "123e4567-e89b-12d3-a456-426614174001", + "page-size": -1, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "org-id": "123e4567-e89b-12d3-a456-426614174000", + "project-id": "123e4567-e89b-12d3-a456-426614174001", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/deploy_components_component_id.json b/tests/CIRCLECI_API/deploy_components_component_id.json new file mode 100644 index 00000000..aa2febc0 --- /dev/null +++ b/tests/CIRCLECI_API/deploy_components_component_id.json @@ -0,0 +1,27 @@ +[ + { + "component_id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "component_id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "component_id": "", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "component_id": "invalid-uuid", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "component_id": "00000000-0000-0000-0000-000000000000", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/deploy_components_component_id_versions.json b/tests/CIRCLECI_API/deploy_components_component_id_versions.json new file mode 100644 index 00000000..f11bf5e4 --- /dev/null +++ b/tests/CIRCLECI_API/deploy_components_component_id_versions.json @@ -0,0 +1,37 @@ +[ + { + "component_id": "abc123", + "environment-id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "component_id": "def456", + "environment-id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "component_id": "ghi789", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "component_id": "invalid_component_id", + "environment-id": "invalid_uuid", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "component_id": "nonexistent_component", + "environment-id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "component_id": "error_component", + "environment-id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/deploy_environments.json b/tests/CIRCLECI_API/deploy_environments.json new file mode 100644 index 00000000..9af4476d --- /dev/null +++ b/tests/CIRCLECI_API/deploy_environments.json @@ -0,0 +1,39 @@ +[ + { + "org-id": "org123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-id": "org123", + "page-size": 10, + "page-token": "token123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-size": 10, + "page-token": "token123", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "org-id": "invalid-org-id", + "page-size": 10, + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "org-id": "org123", + "page-size": -1, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "org-id": "org123", + "page-size": 10, + "page-token": "token123", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/deploy_environments_environment_id.json b/tests/CIRCLECI_API/deploy_environments_environment_id.json new file mode 100644 index 00000000..8d6bda1b --- /dev/null +++ b/tests/CIRCLECI_API/deploy_environments_environment_id.json @@ -0,0 +1,27 @@ +[ + { + "environment_id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "environment_id": "123e4127-e89b-12d3-a456-426123417400", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "environment_id": "", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "environment_id": "invalid-uuid", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "environment_id": "nonexistent-uuid-1234", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_org-slug_summary.json b/tests/CIRCLECI_API/insights_org-slug_summary.json new file mode 100644 index 00000000..cb1d892e --- /dev/null +++ b/tests/CIRCLECI_API/insights_org-slug_summary.json @@ -0,0 +1,44 @@ +[ + { + "org-slug": "valid-org", + "reporting-window": "last-month", + "project-names": { + "project1": "api-preview-docs", + "project2": "backend-service" + }, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug": "valid-org", + "reporting-window": "last-week", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug": "valid-org", + "project-names": { + "project1": "api-preview-docs" + }, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug": "invalid-org", + "reporting-window": "last-month", + "project-names": { + "project1": "api-preview-docs" + }, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug": "valid-org", + "reporting-window": "invalid-window", + "project-names": { + "project1": "api-preview-docs" + }, + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_pages_project-slug_summary.json b/tests/CIRCLECI_API/insights_pages_project-slug_summary.json new file mode 100644 index 00000000..6cbe454c --- /dev/null +++ b/tests/CIRCLECI_API/insights_pages_project-slug_summary.json @@ -0,0 +1,51 @@ +[ + { + "project-slug": "example-project", + "reporting-window": "last-30-days", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "example-project", + "reporting-window": "last-30-days", + "branches": [ + "main", + "develop" + ], + "workflow-names": [ + "build-and-test", + "deploy" + ], + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "reporting-window": "last-30-days", + "branches": [ + "main" + ], + "workflow-names": [ + "build-and-test" + ], + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "reporting-window": "last-30-days", + "branches": [ + "main" + ], + "workflow-names": [ + "build-and-test" + ], + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "reporting-window": "invalid-window", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_branches.json b/tests/CIRCLECI_API/insights_project-slug_branches.json new file mode 100644 index 00000000..7d1dfbb0 --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_branches.json @@ -0,0 +1,30 @@ +[ + { + "project-slug": "valid-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project", + "workflow-name": "build-and-test", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "workflow-name": "build-and-test", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "workflow-name": "build-and-test", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "valid-project", + "workflow-name": "invalid-workflow", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_flaky-tests.json b/tests/CIRCLECI_API/insights_project-slug_flaky-tests.json new file mode 100644 index 00000000..b20be192 --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_flaky-tests.json @@ -0,0 +1,27 @@ +[ + { + "project-slug": "valid-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project-with-optional-fields", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project-slug-123", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "nonexistent-project", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_workflows.json b/tests/CIRCLECI_API/insights_project-slug_workflows.json new file mode 100644 index 00000000..6c5a1783 --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_workflows.json @@ -0,0 +1,42 @@ +[ + { + "project-slug": "example-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "example-project", + "page-token": "abc123", + "all-branches": true, + "branch": "main", + "reporting-window": "last-30-days", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-token": "abc123", + "all-branches": true, + "branch": "main", + "reporting-window": "last-30-days", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "page-token": "invalid-token", + "all-branches": true, + "branch": "main", + "reporting-window": "last-30-days", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "nonexistent-project", + "page-token": "abc123", + "all-branches": true, + "branch": "main", + "reporting-window": "last-30-days", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name.json b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name.json new file mode 100644 index 00000000..99cf2897 --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name.json @@ -0,0 +1,38 @@ +[ + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "all-branches": true, + "branch": "main", + "page-token": "abc123", + "start-date": "2023-01-01", + "end-date": "2023-01-31", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "workflow-name": "build-and-test", + "all-branches": true, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "all-branches": "yes", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "workflow-name": "non-existent-workflow", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_jobs.json b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_jobs.json new file mode 100644 index 00000000..61289e27 --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_jobs.json @@ -0,0 +1,37 @@ +[ + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "page-token": "abc123", + "all-branches": true, + "branch": "main", + "reporting-window": "last-30-days", + "job-name": "test-job", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "workflow-name": "build-and-test", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "all-branches": "yes", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "workflow-name": "build-and-test", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_summ.json b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_summ.json new file mode 100644 index 00000000..7f2d0e2b --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_summ.json @@ -0,0 +1,35 @@ +[ + { + "project-slug": "example-project", + "workflow-name": "build-and-test", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "example-project", + "workflow-name": "deploy", + "all-branches": true, + "branch": "main", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "workflow-name": "build-and-test", + "all-branches": true, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "workflow-name": "build-and-test", + "all-branches": "yes", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "workflow-name": "non-existent-workflow", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_test.json b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_test.json new file mode 100644 index 00000000..230ba725 --- /dev/null +++ b/tests/CIRCLECI_API/insights_project-slug_workflows_workflow-name_test.json @@ -0,0 +1,35 @@ +[ + { + "project-slug": "example-project", + "workflow-name": "build-workflow", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "example-project", + "workflow-name": "build-workflow", + "branch": "main", + "all-branches": true, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "workflow-name": "build-workflow", + "branch": "main", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "workflow-name": "build-workflow", + "branch": 123, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "nonexistent-project", + "workflow-name": "build-workflow", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/insights_time-series_project-slug_workflows_workfl.json b/tests/CIRCLECI_API/insights_time-series_project-slug_workflows_workfl.json new file mode 100644 index 00000000..a4a0266c --- /dev/null +++ b/tests/CIRCLECI_API/insights_time-series_project-slug_workflows_workfl.json @@ -0,0 +1,47 @@ +[ + { + "project-slug": "my-awesome-project", + "workflow-name": "build-and-test", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "my-awesome-project", + "workflow-name": "build-and-test", + "branch": "main", + "granularity": "daily", + "start-date": "2023-01-01", + "end-date": "2023-01-31", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "workflow-name": "build-and-test", + "branch": "main", + "granularity": "daily", + "start-date": "2023-01-01", + "end-date": "2023-01-31", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "my-awesome-project", + "workflow-name": "build-and-test", + "branch": "main", + "granularity": "hourly", + "start-date": "2023-01-01", + "end-date": "2023-01-31", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "non-existent-project", + "workflow-name": "build-and-test", + "branch": "main", + "granularity": "daily", + "start-date": "2023-01-01", + "end-date": "2023-01-31", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/jobs_job-id_cancel.json b/tests/CIRCLECI_API/jobs_job-id_cancel.json new file mode 100644 index 00000000..7d22ea10 --- /dev/null +++ b/tests/CIRCLECI_API/jobs_job-id_cancel.json @@ -0,0 +1,42 @@ +[ + { + "job-id": "valid-job-123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-id": "valid-job-456", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-id": "", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "job-id": "invalid-job-789", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "job-id": "unauthorized-job-000", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "job-id": "forbidden-job-111", + "statusCode": 403, + "scenario": "Client error responses: Forbidden" + }, + { + "job-id": "nonexistent-job-999", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "job-id": "unknown-job-222", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/me.json b/tests/CIRCLECI_API/me.json new file mode 100644 index 00000000..a59b4449 --- /dev/null +++ b/tests/CIRCLECI_API/me.json @@ -0,0 +1,40 @@ +[ + { + "avatar_url": "https://example.com/avatar1.png", + "id": "123e4567-e89b-12d3-a456-426614174000", + "login": "user_login1", + "name": "User One", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "avatar_url": "https://example.com/avatar2.png", + "id": "123e4567-e89b-12d3-a456-426614174001", + "login": "user_login2", + "name": "User Two", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "avatar_url": "https://example.com/avatar3.png", + "id": "123e4567-e89b-12d3-a456-426614174002", + "login": "user_login3", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "avatar_url": "https://example.com/avatar4.png", + "id": "invalid-uuid", + "login": "user_login4", + "name": "User Four", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "avatar_url": "https://example.com/avatar5.png", + "id": "123e4567-e89b-12d3-a456-426614174004", + "name": "User Five", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/me_collaborations.json b/tests/CIRCLECI_API/me_collaborations.json new file mode 100644 index 00000000..4cc8336c --- /dev/null +++ b/tests/CIRCLECI_API/me_collaborations.json @@ -0,0 +1,54 @@ +[ + { + "id": "123e4567-e89b-12d3-a456-426614174000", + "vcs-type": "github", + "name": "Example Organization", + "avatar_url": "https://example.com/avatar.png", + "slug": "example-org", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "123e4567-e89b-12d3-a456-426614174001", + "vcs-type": "bitbucket", + "name": "Another Organization", + "avatar_url": "https://example.com/avatar2.png", + "slug": "another-org", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "123e4567-e89b-12d3-a456-426614174002", + "vcs-type": "gitlab", + "name": "GitLab Organization", + "avatar_url": "https://example.com/avatar3.png", + "slug": "gitlab-org", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "123e4567-e89b-12d3-a456-426614174003", + "vcs-type": "github", + "name": "Missing Avatar", + "slug": "missing-avatar", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "invalid-uuid", + "vcs-type": "unknown-vcs", + "name": "Invalid VCS", + "avatar_url": "https://example.com/avatar4.png", + "slug": "invalid-vcs", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "123e4567-e89b-12d3-a456-426614174004", + "vcs-type": "github", + "name": "No Slug", + "avatar_url": "https://example.com/avatar5.png", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/org_orgID_oidc-custom-claims.json b/tests/CIRCLECI_API/org_orgID_oidc-custom-claims.json new file mode 100644 index 00000000..9fe3f406 --- /dev/null +++ b/tests/CIRCLECI_API/org_orgID_oidc-custom-claims.json @@ -0,0 +1,60 @@ +[ + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "audience": [ + "audience1", + "audience2" + ], + "ttl": "1h", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "audience": [ + "audience1", + "audience2" + ], + "ttl": "1h", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "invalid-uuid", + "audience": [ + "audience1", + "audience2" + ], + "ttl": "1h", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "audience": [ + "audience1", + "audience2" + ], + "ttl": "invalid-ttl", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174999", + "statusCode": 403, + "scenario": "Client error responses: Forbidden" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "audience": [ + "audience1" + ], + "ttl": "1d", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/org_orgID_project_projectID_oidc-custom-claims.json b/tests/CIRCLECI_API/org_orgID_project_projectID_oidc-custom-claims.json new file mode 100644 index 00000000..5e0da35d --- /dev/null +++ b/tests/CIRCLECI_API/org_orgID_project_projectID_oidc-custom-claims.json @@ -0,0 +1,77 @@ +[ + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "projectID": "123e4567-e89b-12d3-a456-426614174001", + "audience": [ + "audience1", + "audience2" + ], + "ttl": "1h", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "projectID": "123e4567-e89b-12d3-a456-426614174001", + "audience": [ + "audience1" + ], + "ttl": "1h", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "invalid-uuid", + "projectID": "123e4567-e89b-12d3-a456-426614174001", + "audience": [ + "audience1" + ], + "ttl": "1h", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "projectID": "invalid-uuid", + "audience": [ + "audience1" + ], + "ttl": "1h", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "projectID": "123e4567-e89b-12d3-a456-426614174001", + "audience": [ + "audience1" + ], + "ttl": "invalid-ttl", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "projectID": "123e4567-e89b-12d3-a456-426614174001", + "audience": [ + "audience1" + ], + "ttl": "1h", + "statusCode": 403, + "scenario": "Client error responses: Forbidden" + }, + { + "orgID": "123e4567-e89b-12d3-a456-426614174000", + "projectID": "123e4567-e89b-12d3-a456-426614174001", + "audience": [ + "audience1" + ], + "ttl": "1h", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organization.json b/tests/CIRCLECI_API/organization.json new file mode 100644 index 00000000..f3db5f75 --- /dev/null +++ b/tests/CIRCLECI_API/organization.json @@ -0,0 +1,30 @@ +[ + { + "name": "Test Organization", + "vcs_type": "github", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "name": "Another Org", + "vcs_type": "gitlab", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "name": "Missing VCS Type", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "name": "Invalid VCS Type", + "vcs_type": "invalid_vcs", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "vcs_type": "github", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organization_org-slug-or-id.json b/tests/CIRCLECI_API/organization_org-slug-or-id.json new file mode 100644 index 00000000..42b65752 --- /dev/null +++ b/tests/CIRCLECI_API/organization_org-slug-or-id.json @@ -0,0 +1,26 @@ +[ + { + "org-slug-or-id": "valid-org-id", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "org-slug-or-id": "valid-org-id-with-optional-fields", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "invalid-org-id", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organization_org-slug-or-id_project.json b/tests/CIRCLECI_API/organization_org-slug-or-id_project.json new file mode 100644 index 00000000..0a84ad9c --- /dev/null +++ b/tests/CIRCLECI_API/organization_org-slug-or-id_project.json @@ -0,0 +1,31 @@ +[ + { + "org-slug-or-id": "gh/CircleCI-Public", + "name": "api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug-or-id": "gh/CircleCI-Public", + "name": "api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug-or-id": "gh/CircleCI-Public", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "invalid-org", + "name": "api-preview-docs", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "gh/CircleCI-Public", + "name": "", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list.json b/tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list.json new file mode 100644 index 00000000..9e05b776 --- /dev/null +++ b/tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list.json @@ -0,0 +1,27 @@ +[ + { + "org-slug-or-id": "valid-org-id", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug-or-id": "valid-org-id", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "invalid-org-id", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "123456", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list_all.json b/tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list_all.json new file mode 100644 index 00000000..c38ec335 --- /dev/null +++ b/tests/CIRCLECI_API/organization_org-slug-or-id_url-orb-allow-list_all.json @@ -0,0 +1,30 @@ +[ + { + "org-slug-or-id": "circleci-org", + "allow-list-entry-id": "ba98990a-5a00-4cad-b55e-b44117b92e0c", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug-or-id": "circleci-org", + "allow-list-entry-id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "nonexistent-org", + "allow-list-entry-id": "ba98990a-5a00-4cad-b55e-b44117b92e0c", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug-or-id": "circleci-org", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "allow-list-entry-id": "ba98990a-5a00-4cad-b55e-b44117b92e0c", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organizations_org_id_groups.json b/tests/CIRCLECI_API/organizations_org_id_groups.json new file mode 100644 index 00000000..9db3284b --- /dev/null +++ b/tests/CIRCLECI_API/organizations_org_id_groups.json @@ -0,0 +1,31 @@ +[ + { + "name": "Development Team", + "description": "Handles all development tasks", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "name": "QA Team", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "name": "", + "description": "Handles testing", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "name": "123InvalidName", + "description": "Handles invalid name scenario", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "name": "NonExistentOrg", + "description": "This organization does not exist", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organizations_org_id_groups_group_id.json b/tests/CIRCLECI_API/organizations_org_id_groups_group_id.json new file mode 100644 index 00000000..65a7efa7 --- /dev/null +++ b/tests/CIRCLECI_API/organizations_org_id_groups_group_id.json @@ -0,0 +1,27 @@ +[ + { + "message": "Group deleted.", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "message": "Permission denied.", + "statusCode": 403, + "scenario": "Client error responses: Forbidden" + }, + { + "message": "Invalid credentials provided.", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "message": "Entity not found.", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "message": "Internal server error.", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organizations_org_id_usage_export_job.json b/tests/CIRCLECI_API/organizations_org_id_usage_export_job.json new file mode 100644 index 00000000..280bbaca --- /dev/null +++ b/tests/CIRCLECI_API/organizations_org_id_usage_export_job.json @@ -0,0 +1,38 @@ +[ + { + "start": "2023-01-01T00:00:00Z", + "end": "2023-01-31T23:59:59Z", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "start": "2023-02-01T00:00:00Z", + "end": "2023-02-28T23:59:59Z", + "shared_org_ids": [ + "org123", + "org456" + ], + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "end": "2023-03-31T23:59:59Z", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "start": "invalid-date", + "end": "2023-04-30T23:59:59Z", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "start": "2023-05-01T00:00:00Z", + "end": "2023-05-31T23:59:59Z", + "shared_org_ids": [ + "invalid-org" + ], + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/organizations_org_id_usage_export_job_usage_export.json b/tests/CIRCLECI_API/organizations_org_id_usage_export_job_usage_export.json new file mode 100644 index 00000000..e996814f --- /dev/null +++ b/tests/CIRCLECI_API/organizations_org_id_usage_export_job_usage_export.json @@ -0,0 +1,66 @@ +[ + { + "usage_export_job_id": "123e4567-e89b-12d3-a456-426614174000", + "state": "completed", + "download_urls": [ + "https://example.com/download/1", + "https://example.com/download/2" + ], + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "usage_export_job_id": "123e4567-e89b-12d3-a456-426614174001", + "state": "in_progress", + "download_urls": [ + "https://example.com/download/3" + ], + "error_reason": "None", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "state": "failed", + "download_urls": [ + "https://example.com/download/4" + ], + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "usage_export_job_id": "invalid-uuid", + "state": "completed", + "download_urls": [ + "https://example.com/download/5" + ], + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "usage_export_job_id": "123e4567-e89b-12d3-a456-426614174002", + "state": "completed", + "download_urls": [ + "https://example.com/download/6" + ], + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "usage_export_job_id": "123e4567-e89b-12d3-a456-426614174003", + "state": "completed", + "download_urls": [ + "https://example.com/download/7" + ], + "statusCode": 429, + "scenario": "Client error responses: Too Many Requests" + }, + { + "usage_export_job_id": "123e4567-e89b-12d3-a456-426614174004", + "state": "completed", + "download_urls": [ + "https://example.com/download/8" + ], + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/owner_ownerID_context_context_decision.json b/tests/CIRCLECI_API/owner_ownerID_context_context_decision.json new file mode 100644 index 00000000..e54e8301 --- /dev/null +++ b/tests/CIRCLECI_API/owner_ownerID_context_context_decision.json @@ -0,0 +1,77 @@ +[ + { + "ownerID": "owner123", + "context": "production", + "input": "{\"key\":\"value\"}", + "metadata": { + "enabled_rules": [ + "rule1", + "rule2" + ], + "status": "active" + }, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "owner123", + "context": "production", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "owner123", + "input": "{\"key\":\"value\"}", + "metadata": { + "enabled_rules": [ + "rule1", + "rule2" + ], + "status": "active" + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "owner123", + "context": "invalid_context", + "input": "{\"key\":\"value\"}", + "metadata": { + "enabled_rules": [ + "rule1", + "rule2" + ], + "status": "active" + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "invalid_owner", + "context": "production", + "input": "{\"key\":\"value\"}", + "metadata": { + "enabled_rules": [ + "rule1", + "rule2" + ], + "status": "active" + }, + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "ownerID": "owner123", + "context": "production", + "input": "{\"key\":\"value\"}", + "metadata": { + "enabled_rules": [ + "rule1", + "rule2" + ], + "status": "active" + }, + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID.json b/tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID.json new file mode 100644 index 00000000..bd4fcd9e --- /dev/null +++ b/tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID.json @@ -0,0 +1,43 @@ +[ + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "dec-001", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "dec-002", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "invalid-uuid", + "context": "production", + "decisionID": "dec-003", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "nonexistent", + "decisionID": "dec-004", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "dec-005", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID_.json b/tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID_.json new file mode 100644 index 00000000..528160b2 --- /dev/null +++ b/tests/CIRCLECI_API/owner_ownerID_context_context_decision_decisionID_.json @@ -0,0 +1,43 @@ +[ + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "decision123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "decision123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "invalid-uuid", + "context": "production", + "decisionID": "decision123", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "nonexistent-decision", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "decisionID": "decision123", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/owner_ownerID_context_context_decision_settings.json b/tests/CIRCLECI_API/owner_ownerID_context_context_decision_settings.json new file mode 100644 index 00000000..532e87eb --- /dev/null +++ b/tests/CIRCLECI_API/owner_ownerID_context_context_decision_settings.json @@ -0,0 +1,56 @@ +[ + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "enabled": true, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "staging", + "enabled": false, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "context": "production", + "enabled": true, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "invalid-uuid", + "context": "production", + "enabled": true, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "invalid_context", + "enabled": true, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "enabled": true, + "statusCode": 403, + "scenario": "Client error responses: Forbidden" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "enabled": true, + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle.json b/tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle.json new file mode 100644 index 00000000..f6089b1d --- /dev/null +++ b/tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle.json @@ -0,0 +1,74 @@ +[ + { + "ownerID": "123e4567-e89b-12d3-a456-426614174000", + "context": "production", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174001", + "context": "staging", + "dry": true, + "policies": { + "created": [ + "policy1", + "policy2" + ], + "deleted": [ + "policy3" + ], + "modified": [ + "policy4" + ] + }, + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "context": "development", + "dry": false, + "policies": { + "created": [ + "policy5" + ] + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "invalid-uuid", + "context": "testing", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174002", + "context": "invalid_context", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174003", + "context": "production", + "dry": true, + "policies": { + "created": [ + "policy6" + ], + "deleted": [ + "policy7" + ], + "modified": [ + "policy8" + ] + }, + "statusCode": 413, + "scenario": "Client error responses: Request Too Long" + }, + { + "ownerID": "123e4567-e89b-12d3-a456-426614174004", + "context": "production", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle_policy.json b/tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle_policy.json new file mode 100644 index 00000000..ef23090b --- /dev/null +++ b/tests/CIRCLECI_API/owner_ownerID_context_context_policy-bundle_policy.json @@ -0,0 +1,43 @@ +[ + { + "content": "Policy content example", + "created_at": "2023-10-01T12:00:00Z", + "created_by": "user123", + "name": "policyName", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "content": "Policy content example", + "created_at": "2023-10-01T12:00:00Z", + "created_by": "user123", + "name": "policyName", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "error": "OwnerID: must be a valid UUID.", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "error": "Unauthorized", + "statusCode": 401, + "scenario": "Client error responses: Unauthorized" + }, + { + "error": "Forbidden", + "statusCode": 403, + "scenario": "Client error responses: Forbidden" + }, + { + "error": "policy not found", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + }, + { + "error": "unexpected server error", + "statusCode": 500, + "scenario": "Server error responses: Internal Server Error" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/pipeline.json b/tests/CIRCLECI_API/pipeline.json new file mode 100644 index 00000000..e0689f2a --- /dev/null +++ b/tests/CIRCLECI_API/pipeline.json @@ -0,0 +1,33 @@ +[ + { + "org-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "org-slug": "gh/CircleCI-Public/api-preview-docs", + "page-token": "abc123", + "mine": true, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-token": "abc123", + "mine": true, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug": "invalid/slug", + "page-token": "abc123", + "mine": true, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "org-slug": "gh/CircleCI-Public/api-preview-docs", + "page-token": "invalid_token", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/pipeline_continue.json b/tests/CIRCLECI_API/pipeline_continue.json new file mode 100644 index 00000000..c562d21e --- /dev/null +++ b/tests/CIRCLECI_API/pipeline_continue.json @@ -0,0 +1,39 @@ +[ + { + "continuation-key": "validKey123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "continuation-key": "validKey456", + "configuration": "configA", + "parameters": { + "param1": "value1", + "param2": "value2" + }, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "configuration": "configB", + "parameters": { + "param1": "value1" + }, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "continuation-key": "invalidKey!", + "configuration": "configC", + "parameters": { + "param1": "value1" + }, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "continuation-key": "nonExistentKey", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/pipeline_pipeline-id.json b/tests/CIRCLECI_API/pipeline_pipeline-id.json new file mode 100644 index 00000000..597379fa --- /dev/null +++ b/tests/CIRCLECI_API/pipeline_pipeline-id.json @@ -0,0 +1,27 @@ +[ + { + "pipeline-id": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "non-existent-id", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/pipeline_pipeline-id_config.json b/tests/CIRCLECI_API/pipeline_pipeline-id_config.json new file mode 100644 index 00000000..df93881d --- /dev/null +++ b/tests/CIRCLECI_API/pipeline_pipeline-id_config.json @@ -0,0 +1,27 @@ +[ + { + "pipeline-id": "pipeline123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "pipeline456", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "pipeline789", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "invalid_pipeline_id", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/pipeline_pipeline-id_values.json b/tests/CIRCLECI_API/pipeline_pipeline-id_values.json new file mode 100644 index 00000000..8bc5846a --- /dev/null +++ b/tests/CIRCLECI_API/pipeline_pipeline-id_values.json @@ -0,0 +1,27 @@ +[ + { + "pipeline-id": "validPipeline123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "validPipeline456", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "invalidPipeline!@#", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "nonExistentPipeline999", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/pipeline_pipeline-id_workflow.json b/tests/CIRCLECI_API/pipeline_pipeline-id_workflow.json new file mode 100644 index 00000000..4cffec8b --- /dev/null +++ b/tests/CIRCLECI_API/pipeline_pipeline-id_workflow.json @@ -0,0 +1,29 @@ +[ + { + "pipeline-id": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "pipeline-id": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "page-token": "abc123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-token": "abc123", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "invalid-uuid", + "page-token": "abc123", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "pipeline-id": "nonexistent-id", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug.json b/tests/CIRCLECI_API/project_project-slug.json new file mode 100644 index 00000000..00313286 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug.json @@ -0,0 +1,27 @@ +[ + { + "project-slug": "valid-project-1", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project-2", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project-@#", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "nonexistent-project", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_checkout-key.json b/tests/CIRCLECI_API/project_project-slug_checkout-key.json new file mode 100644 index 00000000..37a78233 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_checkout-key.json @@ -0,0 +1,31 @@ +[ + { + "project-slug": "example-project", + "type": "deploy-key", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "project-slug": "example-project", + "type": "github-user-key", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "project-slug": "example-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "type": "invalid-key-type", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "nonexistent-project", + "type": "deploy-key", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_checkout-key_fingerprint.json b/tests/CIRCLECI_API/project_project-slug_checkout-key_fingerprint.json new file mode 100644 index 00000000..e2620c62 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_checkout-key_fingerprint.json @@ -0,0 +1,31 @@ +[ + { + "project-slug": "valid-project", + "fingerprint": "valid-fingerprint", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project", + "fingerprint": "valid-fingerprint", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "fingerprint": "valid-fingerprint", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "valid-project", + "fingerprint": "invalid-fingerprint", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_envvar.json b/tests/CIRCLECI_API/project_project-slug_envvar.json new file mode 100644 index 00000000..14057242 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_envvar.json @@ -0,0 +1,35 @@ +[ + { + "project-slug": "my-project", + "name": "foo", + "value": "xxxx1234", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "project-slug": "my-project", + "name": "foo", + "value": "xxxx1234", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "project-slug": "my-project", + "name": "foo", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "my-project", + "value": "xxxx1234", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "name": "foo", + "value": "xxxx1234", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_envvar_name.json b/tests/CIRCLECI_API/project_project-slug_envvar_name.json new file mode 100644 index 00000000..346caf08 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_envvar_name.json @@ -0,0 +1,31 @@ +[ + { + "project-slug": "valid-project", + "name": "valid-name", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project", + "name": "valid-name", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "valid-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid-project", + "name": "valid-name", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "valid-project", + "name": "invalid-name", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_job-number_artifacts.json b/tests/CIRCLECI_API/project_project-slug_job-number_artifacts.json new file mode 100644 index 00000000..92a43abb --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_job-number_artifacts.json @@ -0,0 +1,31 @@ +[ + { + "job-number": "12345", + "project-slug": "example-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "67890", + "project-slug": "another-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "invalid-job-number", + "project-slug": "example-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "12345", + "project-slug": "nonexistent-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "example-project", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_job-number_tests.json b/tests/CIRCLECI_API/project_project-slug_job-number_tests.json new file mode 100644 index 00000000..1fe80e14 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_job-number_tests.json @@ -0,0 +1,31 @@ +[ + { + "job-number": "12345", + "project-slug": "my-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "67890", + "project-slug": "another-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "12345", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "invalid-job-number", + "project-slug": "my-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "12345", + "project-slug": "nonexistent-project", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_job_job-number.json b/tests/CIRCLECI_API/project_project-slug_job_job-number.json new file mode 100644 index 00000000..3f4ab4aa --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_job_job-number.json @@ -0,0 +1,31 @@ +[ + { + "job-number": "12345", + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "67890", + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "12345", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "invalid-job-number", + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "12345", + "project-slug": "invalid/project/slug", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_job_job-number_cancel.json b/tests/CIRCLECI_API/project_project-slug_job_job-number_cancel.json new file mode 100644 index 00000000..31acbdb2 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_job_job-number_cancel.json @@ -0,0 +1,31 @@ +[ + { + "job-number": "12345", + "project-slug": "my-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "job-number": "67890", + "project-slug": "another-project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "missing-job-number", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "invalid-job-number", + "project-slug": "my-project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "job-number": "12345", + "project-slug": "nonexistent-project", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_pipeline.json b/tests/CIRCLECI_API/project_project-slug_pipeline.json new file mode 100644 index 00000000..5027acc1 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_pipeline.json @@ -0,0 +1,30 @@ +[ + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "branch": "feature/design-new-api", + "page-token": "nextPage123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "branch": "feature/design-new-api", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "branch": "invalid-branch-name", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid/project-slug", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_pipeline_mine.json b/tests/CIRCLECI_API/project_project-slug_pipeline_mine.json new file mode 100644 index 00000000..adb153b0 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_pipeline_mine.json @@ -0,0 +1,30 @@ +[ + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "page-token": "abc123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-token": "abc123", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid/slug", + "page-token": "abc123", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "page-token": 12345, + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_pipeline_pipeline-number.json b/tests/CIRCLECI_API/project_project-slug_pipeline_pipeline-number.json new file mode 100644 index 00000000..d497522a --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_pipeline_pipeline-number.json @@ -0,0 +1,31 @@ +[ + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "pipeline-number": "25", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "pipeline-number": "25", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "pipeline-number": "invalid_number", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid/slug", + "pipeline-number": "25", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_project-slug_schedule.json b/tests/CIRCLECI_API/project_project-slug_schedule.json new file mode 100644 index 00000000..4bbb4578 --- /dev/null +++ b/tests/CIRCLECI_API/project_project-slug_schedule.json @@ -0,0 +1,29 @@ +[ + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "page-token": "abc123", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "page-token": "abc123", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "invalid/slug", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "project-slug": "gh/CircleCI-Public/api-preview-docs", + "page-token": "invalid_token", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_provider_organization_project.json b/tests/CIRCLECI_API/project_provider_organization_project.json new file mode 100644 index 00000000..0e902664 --- /dev/null +++ b/tests/CIRCLECI_API/project_provider_organization_project.json @@ -0,0 +1,52 @@ +[ + { + "advanced": { + "autocancel_builds": true + }, + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "advanced": { + "autocancel_builds": true, + "build_fork_prs": false, + "build_prs_only": true, + "disable_ssh": false, + "forks_receive_secret_env_vars": true, + "oss": true, + "set_github_status": false, + "setup_workflows": true, + "write_settings_requires_admin": false, + "pr_only_branch_overrides": [ + "main", + "develop" + ] + }, + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "advanced": { + "build_fork_prs": false + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "advanced": { + "autocancel_builds": "yes" + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "advanced": { + "autocancel_builds": true + }, + "provider": "invalid_provider", + "organization": "valid_org", + "project": "valid_project", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_provider_organization_project_pipeline_run.json b/tests/CIRCLECI_API/project_provider_organization_project_pipeline_run.json new file mode 100644 index 00000000..763a06ec --- /dev/null +++ b/tests/CIRCLECI_API/project_provider_organization_project_pipeline_run.json @@ -0,0 +1,53 @@ +[ + { + "provider": "github", + "organization": "example-org", + "project": "example-project", + "definition_id": "12345", + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "provider": "github", + "organization": "example-org", + "project": "example-project", + "definition_id": "12345", + "config": { + "branch": "main", + "tag": "v1.0" + }, + "checkout": { + "branch": "develop", + "tag": "v1.1" + }, + "parameters": { + "param1": "value1", + "param2": "value2" + }, + "statusCode": 201, + "scenario": "Successful responses: Created" + }, + { + "provider": "github", + "organization": "example-org", + "project": "example-project", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "provider": "invalid-provider", + "organization": "example-org", + "project": "example-project", + "definition_id": "12345", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "provider": "github", + "organization": "nonexistent-org", + "project": "example-project", + "definition_id": "12345", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/project_provider_organization_project_settings.json b/tests/CIRCLECI_API/project_provider_organization_project_settings.json new file mode 100644 index 00000000..3f10f05d --- /dev/null +++ b/tests/CIRCLECI_API/project_provider_organization_project_settings.json @@ -0,0 +1,49 @@ +[ + { + "advanced": { + "autocancel_builds": true + }, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "advanced": { + "autocancel_builds": true, + "build_fork_prs": false, + "build_prs_only": true, + "disable_ssh": false, + "forks_receive_secret_env_vars": true, + "oss": false, + "set_github_status": true, + "setup_workflows": false, + "write_settings_requires_admin": true, + "pr_only_branch_overrides": [ + "main", + "develop" + ] + }, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "advanced": { + "build_fork_prs": false + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "advanced": { + "autocancel_builds": "yes" + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "advanced": { + "autocancel_builds": true + }, + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/projects_project_id_pipeline-definitions.json b/tests/CIRCLECI_API/projects_project_id_pipeline-definitions.json new file mode 100644 index 00000000..7da6b66d --- /dev/null +++ b/tests/CIRCLECI_API/projects_project_id_pipeline-definitions.json @@ -0,0 +1,72 @@ +[ + { + "project_id": "project-123", + "name": "Pipeline A", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project_id": "project-456", + "name": "Pipeline B", + "description": "This is a test pipeline", + "config_source": { + "provider": "github_app", + "repo": { + "external_id": "repo-789" + } + }, + "checkout_source": { + "provider": "github_app", + "repo": { + "external_id": "repo-789" + } + }, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project_id": "project-789", + "name": "Pipeline C", + "config_source": { + "provider": "github_app" + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "project-101", + "name": "Pipeline D", + "config_source": { + "provider": "invalid_provider", + "repo": { + "external_id": "repo-101" + } + }, + "checkout_source": { + "provider": "github_app", + "repo": { + "external_id": "repo-101" + } + }, + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "invalid-project", + "name": "Pipeline E", + "config_source": { + "provider": "github_app", + "repo": { + "external_id": "repo-102" + } + }, + "checkout_source": { + "provider": "github_app", + "repo": { + "external_id": "repo-102" + } + }, + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/projects_project_id_pipeline-definitions_pipeline_.json b/tests/CIRCLECI_API/projects_project_id_pipeline-definitions_pipeline_.json new file mode 100644 index 00000000..90aa46e7 --- /dev/null +++ b/tests/CIRCLECI_API/projects_project_id_pipeline-definitions_pipeline_.json @@ -0,0 +1,68 @@ +[ + { + "project_id": "project123", + "pipeline_definition_id": "pipeline456", + "event_source": { + "provider": "github_app", + "repo": { + "external_id": "repo789" + } + }, + "event_name": "push", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project_id": "project123", + "pipeline_definition_id": "pipeline456", + "event_source": { + "provider": "github_app", + "repo": { + "external_id": "repo789" + } + }, + "event_preset": "all-pushes", + "checkout_ref": "refs/heads/main", + "config_ref": "refs/heads/main", + "event_name": "push", + "disabled": false, + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project_id": "project123", + "pipeline_definition_id": "pipeline456", + "event_source": { + "provider": "github_app" + }, + "event_name": "push", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "project123", + "pipeline_definition_id": "pipeline456", + "event_source": { + "provider": "invalid_provider", + "repo": { + "external_id": "repo789" + } + }, + "event_name": "push", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "invalid_project", + "pipeline_definition_id": "pipeline456", + "event_source": { + "provider": "github_app", + "repo": { + "external_id": "repo789" + } + }, + "event_name": "push", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/projects_project_id_rollback.json b/tests/CIRCLECI_API/projects_project_id_rollback.json new file mode 100644 index 00000000..5ecb01d0 --- /dev/null +++ b/tests/CIRCLECI_API/projects_project_id_rollback.json @@ -0,0 +1,48 @@ +[ + { + "project_id": "proj-12345", + "component_name": "componentA", + "current_version": "1.0.0", + "target_version": "0.9.0", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "project_id": "proj-12345", + "component_name": "componentA", + "current_version": "1.0.0", + "environment_name": "production", + "namespace": "default", + "parameters": { + "key1": "value1", + "key2": "value2" + }, + "reason": "Rollback due to bug", + "target_version": "0.9.0", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "component_name": "componentA", + "current_version": "1.0.0", + "target_version": "0.9.0", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "proj-12345", + "component_name": "componentA", + "current_version": "1.0.0", + "target_version": "invalid_version", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "invalid_proj_id", + "component_name": "componentA", + "current_version": "1.0.0", + "target_version": "0.9.0", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/projects_project_id_triggers_trigger_id.json b/tests/CIRCLECI_API/projects_project_id_triggers_trigger_id.json new file mode 100644 index 00000000..60d4ad62 --- /dev/null +++ b/tests/CIRCLECI_API/projects_project_id_triggers_trigger_id.json @@ -0,0 +1,31 @@ +[ + { + "project_id": "valid_project_123", + "trigger_id": "valid_trigger_456", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project_id": "valid_project_123", + "trigger_id": "valid_trigger_456", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "project_id": "valid_project_123", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "invalid_project_!@#", + "trigger_id": "valid_trigger_456", + "statusCode": 400, + "scenario": "Client error responses: Bad Request" + }, + { + "project_id": "nonexistent_project", + "trigger_id": "nonexistent_trigger", + "statusCode": 404, + "scenario": "Client error responses: Not Found" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/schedule_schedule-id.json b/tests/CIRCLECI_API/schedule_schedule-id.json new file mode 100644 index 00000000..8da73667 --- /dev/null +++ b/tests/CIRCLECI_API/schedule_schedule-id.json @@ -0,0 +1,27 @@ +[ + { + "schedule-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "schedule-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "schedule-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "schedule-id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "schedule-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/test_context_context_id_delete.py b/tests/CIRCLECI_API/test_context_context_id_delete.py new file mode 100644 index 00000000..3def14b3 --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_delete.py @@ -0,0 +1,90 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}_delete for http method type DELETE +# RoostTestHash=5704c86c87 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the DELETE /context/{context_id} API endpoint. + +This test suite covers: +- Successful deletion of a context. +- Unauthorized access due to invalid or missing tokens. +- Not found errors for non-existent contexts. +- Rate limit and server error scenarios. + +Setup: +- Ensure the `conftest.py` and `validator.py` are correctly configured. +- Place `context_context_id.json` in the same directory as this test file. +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'context_context_id.json' +with open(_endpoint_data_path, 'r') as file: + _ENDPOINT_DATA = json.load(file) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_context(api_client, config_test_data, scenario_case): + """ + Test DELETE /context/{context_id} endpoint with various scenarios. + """ + context_id = scenario_case.get('context_id', config_test_data['context_id']) + expected_status_code = scenario_case['statusCode'] + endpoint = f"/context/{context_id}" + + # Prepare headers + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + # Make the DELETE request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == expected_status_code, ( + f"Expected status code {expected_status_code}, got {response.status_code}" + ) + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'DELETE', str(expected_status_code), response + ) + assert validation_result['valid'], ( + f"Response schema validation failed: {validation_result.get('message')}" + ) + + # Additional assertions based on scenario + if expected_status_code == 200: + assert 'message' in response.json(), "Response should contain a 'message' field" + elif expected_status_code == 401: + assert response.json().get('message') == "Invalid token provided.", ( + "Unauthorized response should contain specific message" + ) + elif expected_status_code == 404: + assert response.json().get('message') == "Context not found.", ( + "Not found response should contain specific message" + ) + elif expected_status_code == 429: + assert response.json().get('message') == "Rate limit exceeded.", ( + "Rate limit response should contain specific message" + ) + elif expected_status_code == 500: + assert response.json().get('message') == "Internal server error.", ( + "Server error response should contain specific message" + ) diff --git a/tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_delete.py b/tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_delete.py new file mode 100644 index 00000000..9932ccf1 --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_delete.py @@ -0,0 +1,92 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}/environment-variable/{env_var_name}_delete for http method type DELETE +# RoostTestHash=32e36d7953 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint: /context/{context_id}/environment-variable/{env_var_name} + +This suite tests the DELETE method for removing an environment variable from a context. +It covers various scenarios including successful deletion, unauthorized access, and entity not found. + +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as the JSON test data file. +- Execute the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'context_context_id_environment-variable_env_var_na.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_environment_variable(api_client, config_test_data, scenario_case): + """ + Test DELETE /context/{context_id}/environment-variable/{env_var_name} + """ + context_id = scenario_case.get('context_id', config_test_data['context_id']) + env_var_name = scenario_case.get('env_var_name', config_test_data['env_var_name']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/context/{context_id}/environment-variable/{env_var_name}" + + # Perform DELETE request + try: + response = api_client.delete(endpoint) + except requests.exceptions.HTTPError as e: + response = e.response + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional assertions based on scenario + if expected_status_code == 200: + assert 'message' in response.json(), "Response JSON should contain 'message' key" + elif expected_status_code == 401: + assert response.json().get('message') in [ + "Invalid token provided.", + "New format tokens are needed to authenticate this API endpoint. Create a new API token for access.", + "Support for query parameter authentication has been deprecated to improve security. Please use a supported authentication method such as header-based, or basic authentication." + ], "Unexpected error message for 401 response" + elif expected_status_code == 404: + assert response.json().get('message') in [ + "Context not found.", + "Organization does not exist.", + "User does not exist.", + "Project does not exist.", + "Group does not exist.", + "Orb does not exist." + ], "Unexpected error message for 404 response" + elif expected_status_code == 429: + assert response.json().get('message') == "Rate limit exceeded.", "Unexpected error message for 429 response" + elif expected_status_code == 500: + assert response.json().get('message') == "Internal server error.", "Unexpected error message for 500 response" diff --git a/tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_put.py b/tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_put.py new file mode 100644 index 00000000..650de567 --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_environment-variable_env_var_name_put.py @@ -0,0 +1,84 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}/environment-variable/{env_var_name}_put for http method type PUT +# RoostTestHash=eaadcd9406 +# +# + +# ********RoostGPT******** +""" +Test suite for the API endpoint: /context/{context_id}/environment-variable/{env_var_name} + +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as the JSON test data file. +- Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'context_context_id_environment-variable_env_var_na.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_add_or_update_environment_variable(api_client, config_test_data, scenario_case): + """ + Test the /context/{context_id}/environment-variable/{env_var_name} endpoint. + """ + context_id = scenario_case.get('context_id', config_test_data['context_id']) + env_var_name = scenario_case.get('env_var_name', config_test_data['env_var_name']) + value = scenario_case.get('value', config_test_data.get('value', '')) + + endpoint = f"/context/{context_id}/environment-variable/{env_var_name}" + request_body = {"value": value} + + # Validate request schema + request_validation = validator.validate_json(request_body, 'RequestBodySchema') + assert request_validation['valid'], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.put(endpoint, json=request_body) + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'put', str(scenario_case['statusCode']), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + + # Assert status code + assert response.status_code == scenario_case['statusCode'], f"Expected status code {scenario_case['statusCode']}, got {response.status_code}" + + # Additional assertions based on scenario + if scenario_case['statusCode'] == 200: + response_data = response.json() + assert 'variable' in response_data, "Response missing 'variable'" + assert 'created_at' in response_data, "Response missing 'created_at'" + assert 'updated_at' in response_data, "Response missing 'updated_at'" + assert 'context_id' in response_data, "Response missing 'context_id'" + elif scenario_case['statusCode'] == 401: + assert response.json().get('message') == "Invalid token provided.", "Unexpected error message for 401" + elif scenario_case['statusCode'] == 404: + assert response.json().get('message') == "Context not found.", "Unexpected error message for 404" + elif scenario_case['statusCode'] == 429: + assert response.json().get('message') == "Rate limit exceeded.", "Unexpected error message for 429" + elif scenario_case['statusCode'] == 500: + assert response.json().get('message') == "Internal server error.", "Unexpected error message for 500" diff --git a/tests/CIRCLECI_API/test_context_context_id_environment-variable_get.py b/tests/CIRCLECI_API/test_context_context_id_environment-variable_get.py new file mode 100644 index 00000000..68db0f8f --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_environment-variable_get.py @@ -0,0 +1,148 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}/environment-variable_get for http method type GET +# RoostTestHash=c53c60d621 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /context/{context_id}/environment-variable. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. +- Place the JSON test data file `context_context_id_environment-variable.json` in the same directory. + +Run the tests using the command: +pytest test_api.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'context_context_id_environment-variable.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_environment_variables(api_client, config_test_data, scenario_case): + """ + Test the /context/{context_id}/environment-variable endpoint. + """ + context_id = scenario_case.get('context_id', config_test_data['context_id']) + page_token = scenario_case.get('page-token', None) + expected_status_code = scenario_case['statusCode'] + + # Construct the endpoint URL + endpoint = f"/context/{context_id}/environment-variable" + params = {} + if page_token: + params['page-token'] = page_token + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate the response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("auth_header", [ + ("Bearer invalid_token"), + ("Bearer expired_token"), + ("") +], ids=["invalid_token", "expired_token", "missing_auth"]) +def test_authentication_errors(api_client, config_test_data, auth_header): + """ + Test authentication errors for the /context/{context_id}/environment-variable endpoint. + """ + context_id = config_test_data['context_id'] + endpoint = f"/context/{context_id}/environment-variable" + + # Make the API request with invalid/missing auth + response = api_client.get(endpoint, headers={'Authorization': auth_header}) + + # Validate the response status code + assert response.status_code == 401, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("context_id", [ + ("nonexistent-context-id"), + ("invalid-uuid-format") +], ids=["nonexistent_context", "invalid_uuid"]) +def test_not_found_errors(api_client, context_id): + """ + Test not found errors for the /context/{context_id}/environment-variable endpoint. + """ + endpoint = f"/context/{context_id}/environment-variable" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == 404, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '404', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("rate_limit_exceeded", [True], ids=["rate_limit_exceeded"]) +def test_rate_limit_errors(api_client, rate_limit_exceeded): + """ + Test rate limit errors for the /context/{context_id}/environment-variable endpoint. + """ + if not rate_limit_exceeded: + pytest.skip("Rate limit not exceeded") + + context_id = "valid-context-id" + endpoint = f"/context/{context_id}/environment-variable" + + # Simulate rate limit exceeded + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == 429, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '429', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("server_error", [True], ids=["server_error"]) +def test_internal_server_errors(api_client, server_error): + """ + Test internal server errors for the /context/{context_id}/environment-variable endpoint. + """ + if not server_error: + pytest.skip("Server error not simulated") + + context_id = "valid-context-id" + endpoint = f"/context/{context_id}/environment-variable" + + # Simulate server error + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == 500, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '500', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_context_context_id_get.py b/tests/CIRCLECI_API/test_context_context_id_get.py new file mode 100644 index 00000000..ca10f74d --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_get.py @@ -0,0 +1,84 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}_get for http method type GET +# RoostTestHash=4598a79989 +# +# + +# ********RoostGPT******** +""" +Test suite for the /context/{context_id} endpoint using pytest. + +This suite tests various scenarios including successful retrieval, unauthorized access, +and other error conditions as defined in the API specification. + +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as the `conftest.py` and `validator.py`. +- Use the command `pytest` to execute the tests. + +Dependencies: +- pytest +- requests +- yaml +- jsonschema +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'context_context_id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_context(api_client, config_test_data, scenario_case): + """ + Test the /context/{context_id} endpoint for various scenarios. + """ + context_id = scenario_case.get('context_id', config_test_data['context_id']) + expected_status_code = scenario_case['statusCode'] + endpoint = f"/context/{context_id}" + + # Perform the API request + try: + response = api_client.get(endpoint) + except Exception as e: + if expected_status_code == 401: + pytest.skip(f"Skipping test due to expected unauthorized access: {e}") + else: + raise + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks for specific scenarios + if expected_status_code == 200: + data = response.json() + assert 'id' in data and 'name' in data and 'created_at' in data, "Response missing required fields" + elif expected_status_code == 401: + assert 'message' in response.json(), "Unauthorized response missing 'message' field" + elif expected_status_code == 404: + assert 'message' in response.json(), "Not found response missing 'message' field" + elif expected_status_code == 429: + assert 'message' in response.json(), "Rate limit response missing 'message' field" + elif expected_status_code == 500: + assert 'message' in response.json(), "Internal server error response missing 'message' field" diff --git a/tests/CIRCLECI_API/test_context_context_id_restrictions_get.py b/tests/CIRCLECI_API/test_context_context_id_restrictions_get.py new file mode 100644 index 00000000..c282e3cb --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_restrictions_get.py @@ -0,0 +1,99 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}/restrictions_get for http method type GET +# RoostTestHash=200c0128aa +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the /context/{context_id}/restrictions endpoint. +This suite uses pytest fixtures and the SwaggerSchemaValidator for validating +request and response schemas against the OpenAPI specification. + +Instructions for running the tests: +- Ensure you have pytest installed. +- Place this test file in the same directory as your conftest.py and validator.py. +- Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +swagger_validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'context_context_id_restrictions.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_context_restrictions(api_client, config_test_data, scenario_case): + """ + Test the GET /context/{context_id}/restrictions endpoint with various scenarios. + """ + context_id = scenario_case.get("context_id", config_test_data["context_id"]) + endpoint = f"/context/{context_id}/restrictions" + + # Prepare headers + headers = { + 'Authorization': f"Bearer {api_client.auth['api_key_header']}" + } + + # Make the API request + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == scenario_case["statusCode"], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint, 'GET', str(response.status_code), response + ) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message', '')}" + + # Additional checks based on scenario + if response.status_code == 200: + response_data = response.json() + assert "items" in response_data, "Response missing 'items' key" + for item in scenario_case.get("items", []): + assert item in response_data["items"], f"Expected item {item} not found in response" + +@pytest.mark.parametrize("auth_header", [ + {"Authorization": "Bearer invalid_token"}, + {"Authorization": ""} +], ids=["invalid_token", "missing_token"]) +def test_get_context_restrictions_auth_errors(api_client, auth_header): + """ + Test the GET /context/{context_id}/restrictions endpoint with invalid or missing authentication. + """ + context_id = "123e4567-e89b-12d3-a456-426614174000" # Example context_id + endpoint = f"/context/{context_id}/restrictions" + + # Make the API request + response = api_client.get(endpoint, headers=auth_header) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint, 'GET', '401', response + ) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message', '')}" diff --git a/tests/CIRCLECI_API/test_context_context_id_restrictions_post.py b/tests/CIRCLECI_API/test_context_context_id_restrictions_post.py new file mode 100644 index 00000000..577f6377 --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_restrictions_post.py @@ -0,0 +1,141 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}/restrictions_post for http method type POST +# RoostTestHash=4e2eb4cfcb +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /context/{context_id}/restrictions. + +This test suite covers: +- Endpoint testing for different scenarios including success, client errors, and server errors. +- Security schema testing with valid and invalid credentials. +- Comprehensive coverage of response validation against the OpenAPI spec. + +Instructions: +- Ensure the `conftest.py` and `validator.py` files are in the same directory. +- Place the `context_context_id_restrictions.json` file in the same directory as this test file. +- Run the tests using the pytest command: `pytest .py` + +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'context_context_id_restrictions.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_restriction_success(api_client, config_test_data, scenario_case): + """ + Test the successful creation of context restrictions. + """ + context_id = config_test_data['context_id'] + endpoint = f"/context/{context_id}/restrictions" + payload = { + "restriction_type": scenario_case.get("restriction_type"), + "restriction_value": scenario_case.get("restriction_value") + } + + # Validate request payload + validator.validate_json(payload, "RequestBodySchema") + + response = api_client.post(endpoint, json=payload) + + # Validate response status code + assert response.status_code == scenario_case.get("statusCode") + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_restriction_invalid_auth(api_client, config_test_data, scenario_case): + """ + Test the creation of context restrictions with invalid authentication. + """ + context_id = config_test_data['context_id'] + endpoint = f"/context/{context_id}/restrictions" + payload = { + "restriction_type": scenario_case.get("restriction_type"), + "restriction_value": scenario_case.get("restriction_value") + } + + # Use invalid token + invalid_auth = {'Authorization': 'Bearer invalid_token'} + response = api_client.post(endpoint, json=payload, headers=invalid_auth) + + # Validate response status code + assert response.status_code == 401 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', '401', response) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_restriction_missing_auth(api_client, config_test_data, scenario_case): + """ + Test the creation of context restrictions without authentication. + """ + context_id = config_test_data['context_id'] + endpoint = f"/context/{context_id}/restrictions" + payload = { + "restriction_type": scenario_case.get("restriction_type"), + "restriction_value": scenario_case.get("restriction_value") + } + + # Make request without auth header + response = api_client.post(endpoint, json=payload, headers={}) + + # Validate response status code + assert response.status_code == 401 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', '401', response) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_restriction_bad_request(api_client, config_test_data, scenario_case): + """ + Test the creation of context restrictions with invalid payload. + """ + context_id = config_test_data['context_id'] + endpoint = f"/context/{context_id}/restrictions" + payload = { + "restriction_type": "invalid_type", + "restriction_value": scenario_case.get("restriction_value") + } + + # Validate request payload + validator.validate_json(payload, "RequestBodySchema") + + response = api_client.post(endpoint, json=payload) + + # Validate response status code + assert response.status_code == 400 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', '400', response) + assert validation_result['valid'], validation_result.get('message', '') diff --git a/tests/CIRCLECI_API/test_context_context_id_restrictions_restriction_id_delete.py b/tests/CIRCLECI_API/test_context_context_id_restrictions_restriction_id_delete.py new file mode 100644 index 00000000..c7e8025c --- /dev/null +++ b/tests/CIRCLECI_API/test_context_context_id_restrictions_restriction_id_delete.py @@ -0,0 +1,102 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context/{context_id}/restrictions/{restriction_id}_delete for http method type DELETE +# RoostTestHash=ac183fbd06 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /context/{context_id}/restrictions/{restriction_id} + +Setup: +- Ensure the `conftest.py` and `validator.py` are in the same directory. +- The `config.yml` file should be configured with the necessary API host and authentication details. +- The JSON test data file `context_context_id_restrictions_restriction_id.json` should be present in the same directory. + +Run the tests using the command: +pytest .py +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Constants +TEST_DATA_FILENAME = 'context_context_id_restrictions_restriction_id.json' +API_SPEC_PATH = 'api.json' +ENDPOINT = '/context/{context_id}/restrictions/{restriction_id}' +METHOD = 'DELETE' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +# Initialize SwaggerSchemaValidator +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_context_restriction(api_client, config_test_data, scenario_case): + """ + Test the DELETE /context/{context_id}/restrictions/{restriction_id} endpoint. + """ + context_id = config_test_data['context_id'] + restriction_id = config_test_data['restriction_id'] + endpoint = ENDPOINT.format(context_id=context_id, restriction_id=restriction_id) + + # Prepare headers + headers = { + 'Authorization': f"Bearer {api_client.auth['api_key_header']}" + } + + # Make API request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, METHOD, str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Validate response message + response_data = response.json() + assert response_data['message'] == scenario_case['message'], f"Expected message '{scenario_case['message']}', got '{response_data['message']}'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_context_restriction_invalid_auth(api_client, config_test_data, scenario_case): + """ + Test the DELETE /context/{context_id}/restrictions/{restriction_id} endpoint with invalid authentication. + """ + context_id = config_test_data['context_id'] + restriction_id = config_test_data['restriction_id'] + endpoint = ENDPOINT.format(context_id=context_id, restriction_id=restriction_id) + + # Prepare headers with invalid token + headers = { + 'Authorization': 'Bearer invalid_token' + } + + # Make API request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, METHOD, '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Validate response message + response_data = response.json() + expected_message = "Invalid token provided." + assert response_data['message'] == expected_message, f"Expected message '{expected_message}', got '{response_data['message']}'" diff --git a/tests/CIRCLECI_API/test_context_get.py b/tests/CIRCLECI_API/test_context_get.py new file mode 100644 index 00000000..7ad8ae9e --- /dev/null +++ b/tests/CIRCLECI_API/test_context_get.py @@ -0,0 +1,105 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context_get for http method type GET +# RoostTestHash=fa14dfa4fb +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /context API endpoint. + +This test suite covers various scenarios for the /context endpoint, including +authentication, response validation, and error handling. The tests are designed +to be comprehensive and maintainable, leveraging fixtures and parameterized tests. + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place this test file in the same directory as the `conftest.py` and `validator.py`. +3. Run the tests using the command: `pytest .py` + +Note: The test data is loaded from `context.json` and `config.yml`. +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +swagger_validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'context.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_contexts(api_client, config_test_data, scenario_case): + """ + Test the /context endpoint for various scenarios. + """ + # Prepare request parameters + params = { + 'owner-id': scenario_case.get('owner-id', config_test_data.get('ownerID')), + 'owner-slug': scenario_case.get('owner-slug'), + 'owner-type': scenario_case.get('owner-type'), + 'page-token': scenario_case.get('page-token') + } + # Remove None values from params + params = {k: v for k, v in params.items() if v is not None} + + # Make the API request + response = api_client.get('/context', params=params) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint='/context', + method='GET', + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_contexts_invalid_auth(api_client, scenario_case): + """ + Test the /context endpoint with invalid authentication. + """ + # Prepare request parameters + params = { + 'owner-id': scenario_case.get('owner-id'), + 'owner-slug': scenario_case.get('owner-slug'), + 'owner-type': scenario_case.get('owner-type'), + 'page-token': scenario_case.get('page-token') + } + # Remove None values from params + params = {k: v for k, v in params.items() if v is not None} + + # Override headers with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + + # Make the API request + response = api_client.get('/context', params=params, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint='/context', + method='GET', + status_code='401', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_context_post.py b/tests/CIRCLECI_API/test_context_post.py new file mode 100644 index 00000000..19991e09 --- /dev/null +++ b/tests/CIRCLECI_API/test_context_post.py @@ -0,0 +1,163 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /context_post for http method type POST +# RoostTestHash=537365dd8f +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'context.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['name'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_success(api_client, config_test_data, scenario_case): + """ + Test creating a context with valid data + """ + # Prepare request data + request_data = { + "name": scenario_case["name"], + "owner": scenario_case["owner"] + } + + # Validate request schema + validation_result = validator.validate_json(request_data, "Context") + assert validation_result["valid"], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post("/context", json=request_data) + + # Validate response status code + assert response.status_code == scenario_case["statusCode"], f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/context", "post", str(response.status_code), response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_invalid_auth(api_client, scenario_case): + """ + Test creating a context with invalid authentication + """ + # Prepare request data + request_data = { + "name": scenario_case["name"], + "owner": scenario_case["owner"] + } + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.post("/context", json=request_data, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/context", "post", "401", response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_missing_auth(api_client, scenario_case): + """ + Test creating a context without authentication + """ + # Prepare request data + request_data = { + "name": scenario_case["name"], + "owner": scenario_case["owner"] + } + + # Make API request without token + response = api_client.post("/context", json=request_data, headers={}) + + # Validate response status code + assert response.status_code == 401, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/context", "post", "401", response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_entity_not_found(api_client, scenario_case): + """ + Test creating a context with non-existent entity + """ + # Prepare request data with non-existent owner ID + request_data = { + "name": scenario_case["name"], + "owner": { + "id": "non-existent-id", + "type": scenario_case["owner"]["type"] + } + } + + # Make API request + response = api_client.post("/context", json=request_data) + + # Validate response status code + assert response.status_code == 404, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/context", "post", "404", response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_rate_limit_exceeded(api_client, scenario_case): + """ + Test creating a context when rate limit is exceeded + """ + # Prepare request data + request_data = { + "name": scenario_case["name"], + "owner": scenario_case["owner"] + } + + # Simulate rate limit exceeded + response = api_client.post("/context", json=request_data) + + # Validate response status code + if response.status_code == 429: + validation_result = validator.validate_schema_by_response("/context", "post", "429", response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + else: + pytest.skip(f"Rate limit not exceeded, received status code: {response.status_code}") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_context_internal_server_error(api_client, scenario_case): + """ + Test creating a context with server error + """ + # Prepare request data + request_data = { + "name": scenario_case["name"], + "owner": scenario_case["owner"] + } + + # Simulate server error + response = api_client.post("/context", json=request_data) + + # Validate response status code + if response.status_code == 500: + validation_result = validator.validate_schema_by_response("/context", "post", "500", response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + else: + pytest.skip(f"Server error not encountered, received status code: {response.status_code}") diff --git a/tests/CIRCLECI_API/test_deploy_components_component_id_get.py b/tests/CIRCLECI_API/test_deploy_components_component_id_get.py new file mode 100644 index 00000000..9b0138b7 --- /dev/null +++ b/tests/CIRCLECI_API/test_deploy_components_component_id_get.py @@ -0,0 +1,107 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /deploy/components/{component_id}_get for http method type GET +# RoostTestHash=a5ad0e3f80 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /deploy/components/{component_id}. +This suite tests various scenarios including successful responses, client errors, and server errors. +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'deploy_components_component_id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_component(api_client, scenario_case, config_test_data): + """ + Test the GET /deploy/components/{component_id} endpoint. + """ + component_id = scenario_case.get('component_id', config_test_data['component_id']) + status_code = scenario_case['statusCode'] + endpoint = f"/deploy/components/{component_id}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == status_code, f"Expected {status_code}, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_component_invalid_auth(api_client, scenario_case): + """ + Test the GET /deploy/components/{component_id} endpoint with invalid authentication. + """ + component_id = scenario_case.get('component_id') + endpoint = f"/deploy/components/{component_id}" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate the response status code for unauthorized access + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_component_not_found(api_client, scenario_case): + """ + Test the GET /deploy/components/{component_id} endpoint for a non-existent component. + """ + component_id = "non-existent-id" + endpoint = f"/deploy/components/{component_id}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code for not found + assert response.status_code == 404, f"Expected 404, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '404', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_component_server_error(api_client, scenario_case): + """ + Test the GET /deploy/components/{component_id} endpoint for server error simulation. + """ + component_id = scenario_case.get('component_id') + endpoint = f"/deploy/components/{component_id}" + + # Simulate server error by mocking the response (not shown here) + # response = mock_server_error_response() + + # Validate the response status code for server error + # assert response.status_code == 500, f"Expected 500, got {response.status_code}" + + # Validate the response schema + # validation_result = validator.validate_schema_by_response(endpoint, 'GET', '500', response) + # assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + pytest.skip("Server error simulation not implemented") diff --git a/tests/CIRCLECI_API/test_deploy_components_component_id_versions_get.py b/tests/CIRCLECI_API/test_deploy_components_component_id_versions_get.py new file mode 100644 index 00000000..a6f4bde7 --- /dev/null +++ b/tests/CIRCLECI_API/test_deploy_components_component_id_versions_get.py @@ -0,0 +1,96 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /deploy/components/{component_id}/versions_get for http method type GET +# RoostTestHash=f5d2c83bd0 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /deploy/components/{component_id}/versions. + +This test suite covers: +- All response status codes defined in the API spec. +- Security schema testing with valid and invalid credentials. +- Validation of request and response schemas using SwaggerSchemaValidator. + +To run the tests: +1. Ensure pytest and all dependencies are installed. +2. Execute `pytest` in the terminal within the directory containing this file. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'deploy_components_component_id_versions.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +@pytest.fixture(scope='module') +def endpoint_data(): + return _ENDPOINT_DATA + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=lambda x: x['scenario']) +def test_list_component_versions(api_client, config_test_data, scenario_case): + """ + Test the /deploy/components/{component_id}/versions endpoint. + """ + component_id = scenario_case.get('component_id', config_test_data['component_id']) + environment_id = scenario_case.get('environment-id', config_test_data['environment_id']) + expected_status_code = scenario_case['statusCode'] + + # Construct the endpoint URL + endpoint = f"/deploy/components/{component_id}/versions" + params = {} + if environment_id: + params['environment-id'] = environment_id + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate the response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=lambda x: x['scenario']) +def test_list_component_versions_invalid_auth(api_client, scenario_case): + """ + Test the /deploy/components/{component_id}/versions endpoint with invalid authentication. + """ + component_id = scenario_case.get('component_id') + environment_id = scenario_case.get('environment-id') + + # Construct the endpoint URL + endpoint = f"/deploy/components/{component_id}/versions" + params = {} + if environment_id: + params['environment-id'] = environment_id + + # Make the API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers, params=params) + + # Validate the response status code for unauthorized access + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_deploy_components_get.py b/tests/CIRCLECI_API/test_deploy_components_get.py new file mode 100644 index 00000000..de7f2da6 --- /dev/null +++ b/tests/CIRCLECI_API/test_deploy_components_get.py @@ -0,0 +1,102 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /deploy/components_get for http method type GET +# RoostTestHash=dac5650099 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /deploy/components. + +This suite tests the endpoint for various scenarios including valid and invalid requests, +authentication, and response validation against the OpenAPI specification. + +Setup: +- Ensure the config.yml file is correctly configured with the API host and authentication details. +- The deploy_components.json file should be present in the same directory as this test file. + +Execution: +- Run the tests using pytest in the command line: `pytest test_deploy_components.py` +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'deploy_components.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_components(api_client, config_test_data, scenario_case): + """ + Test the /deploy/components endpoint with various scenarios. + """ + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct query parameters + params = { + "org-id": test_data.get("org-id"), + "project-id": test_data.get("project-id"), + "page-size": test_data.get("page-size"), + "page-token": test_data.get("page-token") + } + + # Remove None values + params = {k: v for k, v in params.items() if v is not None} + + # Validate request schema before sending + request_validation = validator.validate_json(params, "ListComponentsRequest") + assert request_validation["valid"], f"Request validation failed: {request_validation['message']}" + + # Make API request + response = api_client.get("/deploy/components", params=params) + + # Validate response status code + assert response.status_code == scenario_case["statusCode"], f"Expected status code {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response("/deploy/components", "get", str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_components_invalid_auth(api_client, scenario_case): + """ + Test the /deploy/components endpoint with invalid authentication. + """ + # Construct query parameters + params = { + "org-id": scenario_case.get("org-id"), + "project-id": scenario_case.get("project-id"), + "page-size": scenario_case.get("page-size"), + "page-token": scenario_case.get("page-token") + } + + # Remove None values + params = {k: v for k, v in params.items() if v is not None} + + # Make API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get("/deploy/components", params=params, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected status code 401, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response("/deploy/components", "get", "401", response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" diff --git a/tests/CIRCLECI_API/test_deploy_environments_environment_id_get.py b/tests/CIRCLECI_API/test_deploy_environments_environment_id_get.py new file mode 100644 index 00000000..84d2ae87 --- /dev/null +++ b/tests/CIRCLECI_API/test_deploy_environments_environment_id_get.py @@ -0,0 +1,99 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /deploy/environments/{environment_id}_get for http method type GET +# RoostTestHash=8f339ca0a4 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /deploy/environments/{environment_id}. +This suite tests various scenarios including successful responses, client errors, and server errors. +Ensure to have the necessary configurations in config.yml and deploy_environments_environment_id.json for test data. +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'deploy_environments_environment_id.json' + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_environment(api_client, config_test_data, scenario_case): + """ + Test the GET /deploy/environments/{environment_id} endpoint. + """ + environment_id = scenario_case.get("environment_id", config_test_data["environment_id"]) + expected_status_code = scenario_case["statusCode"] + + # Validate request before sending + validator.validate_json({"environment_id": environment_id}, "EnvironmentIdSchema") + + # Make the API call + response = api_client.get(f"/deploy/environments/{environment_id}") + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + "/deploy/environments/{environment_id}", "get", str(expected_status_code), response + ) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_environment_invalid_auth(api_client, scenario_case): + """ + Test the GET /deploy/environments/{environment_id} endpoint with invalid authentication. + """ + environment_id = scenario_case.get("environment_id", "invalid-id") + headers = {"Authorization": "Bearer invalid_token"} + + # Make the API call + response = api_client.get(f"/deploy/environments/{environment_id}", headers=headers) + + # Validate response status code + assert response.status_code == 401, "Expected 401 Unauthorized for invalid token" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + "/deploy/environments/{environment_id}", "get", "401", response + ) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_environment_not_found(api_client, scenario_case): + """ + Test the GET /deploy/environments/{environment_id} endpoint for a non-existent environment. + """ + environment_id = "non-existent-id" + + # Make the API call + response = api_client.get(f"/deploy/environments/{environment_id}") + + # Validate response status code + assert response.status_code == 404, "Expected 404 Not Found for non-existent environment" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + "/deploy/environments/{environment_id}", "get", "404", response + ) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_deploy_environments_get.py b/tests/CIRCLECI_API/test_deploy_environments_get.py new file mode 100644 index 00000000..fd7ae83a --- /dev/null +++ b/tests/CIRCLECI_API/test_deploy_environments_get.py @@ -0,0 +1,122 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /deploy/environments_get for http method type GET +# RoostTestHash=f8bd2fc8fe +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / "deploy_environments.json" +with open(_endpoint_data_path, "r") as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i, _ in enumerate(_ENDPOINT_DATA)] + +# Initialize SwaggerSchemaValidator +swagger_validator = SwaggerSchemaValidator("api.json") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_environments(api_client, config_test_data, scenario_case): + """ + Test the /deploy/environments endpoint for various scenarios. + """ + # Prepare request parameters + org_id = scenario_case.get("org-id", config_test_data["org_id"]) + page_size = scenario_case.get("page-size", None) + page_token = scenario_case.get("page-token", None) + + # Construct query parameters + params = {"org-id": org_id} + if page_size is not None: + params["page-size"] = page_size + if page_token is not None: + params["page-token"] = page_token + + # Validate request schema + swagger_validator.validate_json(params, "ListEnvironmentsRequest") + + # Make API request + response = api_client.get("/deploy/environments", params=params) + + # Validate response status code + assert response.status_code == scenario_case["statusCode"] + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + "/deploy/environments", "get", str(response.status_code), response + ) + assert validation_result["valid"], validation_result.get("message", "") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_environments_invalid_auth(api_client, scenario_case): + """ + Test the /deploy/environments endpoint with invalid authentication. + """ + # Prepare request parameters + org_id = scenario_case.get("org-id", "invalid-org-id") + params = {"org-id": org_id} + + # Make API request with invalid token + response = api_client.get("/deploy/environments", params=params, headers={"Authorization": "Bearer invalid_token"}) + + # Validate response status code for invalid auth + assert response.status_code == 401 + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + "/deploy/environments", "get", "401", response + ) + assert validation_result["valid"], validation_result.get("message", "") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_environments_missing_auth(api_client, scenario_case): + """ + Test the /deploy/environments endpoint with missing authentication. + """ + # Prepare request parameters + org_id = scenario_case.get("org-id", "missing-auth-org-id") + params = {"org-id": org_id} + + # Make API request without auth header + response = api_client.get("/deploy/environments", params=params, headers={}) + + # Validate response status code for missing auth + assert response.status_code == 401 + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + "/deploy/environments", "get", "401", response + ) + assert validation_result["valid"], validation_result.get("message", "") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_environments_not_found(api_client, scenario_case): + """ + Test the /deploy/environments endpoint for not found scenarios. + """ + # Prepare request parameters + org_id = scenario_case.get("org-id", "non-existent-org-id") + params = {"org-id": org_id} + + # Make API request + response = api_client.get("/deploy/environments", params=params) + + # Validate response status code for not found + assert response.status_code == 404 + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + "/deploy/environments", "get", "404", response + ) + assert validation_result["valid"], validation_result.get("message", "") diff --git a/tests/CIRCLECI_API/test_insights_org-slug_summary_get.py b/tests/CIRCLECI_API/test_insights_org-slug_summary_get.py new file mode 100644 index 00000000..6162ffc5 --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_org-slug_summary_get.py @@ -0,0 +1,124 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{org-slug}/summary_get for http method type GET +# RoostTestHash=84690151ce +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /insights/{org-slug}/summary API endpoint. + +This test suite covers: +- Successful responses with valid authentication and parameters. +- Error responses for invalid/missing authentication. +- Validation of response schemas against the OpenAPI specification. + +Instructions for running the tests: +1. Ensure pytest is installed: `pip install pytest` +2. Run the tests using the command: `pytest .py` +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / "api.json" +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / "insights_org-slug_summary.json" +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_org_summary_success(api_client, config_test_data, scenario_case): + """ + Test successful retrieval of org summary metrics with valid credentials. + """ + org_slug = scenario_case.get("org-slug", config_test_data['org-slug']) + reporting_window = scenario_case.get("reporting-window", "last-90-days") + project_names = scenario_case.get("project-names", {}) + + # Construct query parameters + params = {"reporting-window": reporting_window} + if project_names: + for key, value in project_names.items(): + params[f"project-names"] = value + + # Make the API request + response = api_client.get(f"/insights/{org_slug}/summary", params=params) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'] + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/insights/{org_slug}/summary", + method="GET", + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_org_summary_invalid_auth(api_client, scenario_case): + """ + Test retrieval of org summary metrics with invalid authentication. + """ + org_slug = scenario_case.get("org-slug", "invalid-org") + reporting_window = scenario_case.get("reporting-window", "last-90-days") + + # Construct query parameters + params = {"reporting-window": reporting_window} + + # Make the API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(f"/insights/{org_slug}/summary", params=params, headers=headers) + + # Validate response status code + assert response.status_code != 200 + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/insights/{org_slug}/summary", + method="GET", + status_code='default', + response=response + ) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_org_summary_missing_auth(api_client, scenario_case): + """ + Test retrieval of org summary metrics without authentication. + """ + org_slug = scenario_case.get("org-slug", "valid-org") + reporting_window = scenario_case.get("reporting-window", "last-90-days") + + # Construct query parameters + params = {"reporting-window": reporting_window} + + # Make the API request without token + response = api_client.get(f"/insights/{org_slug}/summary", params=params, headers={}) + + # Validate response status code + assert response.status_code != 200 + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/insights/{org_slug}/summary", + method="GET", + status_code='default', + response=response + ) + assert validation_result['valid'], validation_result.get('message', '') diff --git a/tests/CIRCLECI_API/test_insights_pages_project-slug_summary_get.py b/tests/CIRCLECI_API/test_insights_pages_project-slug_summary_get.py new file mode 100644 index 00000000..3f6e830b --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_pages_project-slug_summary_get.py @@ -0,0 +1,86 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/pages/{project-slug}/summary_get for http method type GET +# RoostTestHash=3d4b283b09 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for CircleCI Insights API. + +This suite tests the `/insights/pages/{project-slug}/summary` endpoint. +Ensure `config.yml` is properly set up with necessary API credentials. + +To run the tests: +1. Install dependencies: `pip install -r requirements.txt` +2. Execute tests: `pytest test_insights_api.py` +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_pages_project-slug_summary.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=lambda x: x['scenario']) +def test_get_insights_summary(api_client, config_test_data, scenario_case): + """ + Test the `/insights/pages/{project-slug}/summary` endpoint. + """ + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + reporting_window = scenario_case.get('reporting-window', 'last-90-days') + branches = scenario_case.get('branches', []) + workflow_names = scenario_case.get('workflow-names', []) + + # Construct query parameters + params = {'reporting-window': reporting_window} + if branches: + params['branches'] = branches + if workflow_names: + params['workflow-names'] = workflow_names + + # Make the API request + endpoint = f"/insights/pages/{project_slug}/summary" + response = api_client.get(endpoint, params=params) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=lambda x: x['scenario']) +def test_get_insights_summary_invalid_auth(api_client, scenario_case): + """ + Test the `/insights/pages/{project-slug}/summary` endpoint with invalid authentication. + """ + project_slug = scenario_case.get('project-slug', 'invalid-project') + reporting_window = scenario_case.get('reporting-window', 'last-90-days') + + # Construct query parameters + params = {'reporting-window': reporting_window} + + # Make the API request with invalid auth + endpoint = f"/insights/pages/{project_slug}/summary" + response = api_client.get(endpoint, params=params, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_branches_get.py b/tests/CIRCLECI_API/test_insights_project-slug_branches_get.py new file mode 100644 index 00000000..79271690 --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_branches_get.py @@ -0,0 +1,105 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/branches_get for http method type GET +# RoostTestHash=09a8ae2e85 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_project-slug_branches.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}_{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_all_insights_branches(api_client, config_test_data, scenario_case): + """ + Test the /insights/{project-slug}/branches endpoint for various scenarios. + """ + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + workflow_name = scenario_case.get('workflow-name', config_test_data.get('workflow-name')) + expected_status_code = scenario_case['statusCode'] + + # Construct the endpoint path + endpoint = f"insights/{project_slug}/branches" + params = {} + if workflow_name: + params['workflow-name'] = workflow_name + + # Validate request schema + request_data = {'project-slug': project_slug} + validator.validate_json(request_data, 'GetAllInsightsBranchesRequest') + + # Make the API request + try: + response = api_client.get(endpoint, params=params) + except requests.exceptions.HTTPError as e: + if e.response.status_code == expected_status_code: + response = e.response + else: + pytest.fail(f"Unexpected HTTP error: {e}") + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code=str(expected_status_code), + response=response + ) + + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + + # Additional assertions based on expected status code + if expected_status_code == 200: + assert 'org_id' in response.json(), "Missing 'org_id' in response" + assert 'project_id' in response.json(), "Missing 'project_id' in response" + assert 'branches' in response.json(), "Missing 'branches' in response" + else: + assert 'message' in response.json(), "Missing 'message' in error response" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_all_insights_branches_invalid_auth(api_client, scenario_case): + """ + Test the /insights/{project-slug}/branches endpoint with invalid authentication. + """ + project_slug = scenario_case.get('project-slug', 'invalid-project') + workflow_name = scenario_case.get('workflow-name', None) + expected_status_code = 401 # Unauthorized + + # Construct the endpoint path + endpoint = f"insights/{project_slug}/branches" + params = {} + if workflow_name: + params['workflow-name'] = workflow_name + + # Make the API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.get(f"{api_client.host}/{endpoint}", headers=headers, params=params) + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code=str(expected_status_code), + response=response + ) + + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + assert response.status_code == expected_status_code, f"Expected status code {expected_status_code}, got {response.status_code}" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_flaky-tests_get.py b/tests/CIRCLECI_API/test_insights_project-slug_flaky-tests_get.py new file mode 100644 index 00000000..ed9631a8 --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_flaky-tests_get.py @@ -0,0 +1,106 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/flaky-tests_get for http method type GET +# RoostTestHash=abf46592e1 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +swagger_validator = SwaggerSchemaValidator('api.json') + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_project-slug_flaky-tests.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_flaky_tests_smoke_success(api_client, config_test_data, scenario_case): + """ + Test the GET /insights/{project-slug}/flaky-tests endpoint for successful responses. + """ + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + endpoint = f"insights/{project_slug}/flaky-tests" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']} but got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_flaky_tests_invalid_auth(api_client, scenario_case): + """ + Test the GET /insights/{project-slug}/flaky-tests endpoint with invalid authentication. + """ + project_slug = scenario_case.get('project-slug', 'invalid-project') + endpoint = f"insights/{project_slug}/flaky-tests" + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code != 200, "Expected non-200 status code for invalid auth" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_flaky_tests_missing_auth(api_client, scenario_case): + """ + Test the GET /insights/{project-slug}/flaky-tests endpoint with missing authentication. + """ + project_slug = scenario_case.get('project-slug', 'missing-auth-project') + endpoint = f"insights/{project_slug}/flaky-tests" + + # Make API request without token + headers = {} + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code != 200, "Expected non-200 status code for missing auth" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +""" +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as the JSON test data file. +- Run the tests using the command: pytest .py +""" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_workflows_get.py b/tests/CIRCLECI_API/test_insights_project-slug_workflows_get.py new file mode 100644 index 00000000..afe5429f --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_workflows_get.py @@ -0,0 +1,124 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/workflows_get for http method type GET +# RoostTestHash=a3d95b97e2 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI Insights API. + +Setup Instructions: +1. Ensure `conftest.py` and `validator.py` are in the same directory as this test file. +2. Ensure `config.yml` is configured with the correct API host and authentication details. +3. Place `insights_project-slug_workflows.json` in the same directory for test data. +4. Run the tests using `pytest`. + +This test suite covers: +- Endpoint: /insights/{project-slug}/workflows +- Method: GET +- Security: API Key in Header +- Response Codes: 200, default (error) +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_project-slug_workflows.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_workflow_metrics(api_client, config_test_data, scenario_case): + """ + Test the GET /insights/{project-slug}/workflows endpoint. + """ + + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + project_slug = test_data['project-slug'] + endpoint = f"/insights/{project_slug}/workflows" + + # Prepare query parameters + params = {} + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'reporting-window' in test_data: + params['reporting-window'] = test_data['reporting-window'] + + # Validate request schema + validator.validate_json(params, 'QueryParameters') + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate response schema + status_code = str(scenario_case['statusCode']) + validation_result = validator.validate_schema_by_response(endpoint, 'GET', status_code, response) + + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" + + # Additional assertions based on status code + if status_code == '200': + response_data = response.json() + assert 'items' in response_data, "Response missing 'items'" + assert isinstance(response_data['items'], list), "'items' should be a list" + else: + assert status_code != '200', "Unexpected success response for error scenario" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_workflow_metrics_invalid_auth(api_client, scenario_case): + """ + Test the GET /insights/{project-slug}/workflows endpoint with invalid authentication. + """ + + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + project_slug = test_data['project-slug'] + endpoint = f"/insights/{project_slug}/workflows" + + # Prepare query parameters + params = {} + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'reporting-window' in test_data: + params['reporting-window'] = test_data['reporting-window'] + + # Validate request schema + validator.validate_json(params, 'QueryParameters') + + # Make the API request with invalid auth + response = api_client.get(endpoint, params=params, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" + assert response.status_code != 200, "Unexpected success response for invalid auth" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_get.py b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_get.py new file mode 100644 index 00000000..1b343948 --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_get.py @@ -0,0 +1,113 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/workflows/{workflow-name}_get for http method type GET +# RoostTestHash=e7554c4ea6 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI Insights API. + +This test suite covers the `/insights/{project-slug}/workflows/{workflow-name}` endpoint. +It includes tests for successful responses, error handling, and security schema validation. + +To run the tests, use the following command: +pytest .py + +Ensure that the `conftest.py` and `validator.py` files are in the same directory. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_project-slug_workflows_workflow-name.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_workflow_runs(api_client, config_test_data, scenario_case): + """ + Test the GET /insights/{project-slug}/workflows/{workflow-name} endpoint. + + This test checks for successful responses, error handling, and schema validation. + """ + # Override default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint path + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}" + + # Prepare query parameters + params = {} + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + if 'start-date' in test_data: + params['start-date'] = test_data['start-date'] + if 'end-date' in test_data: + params['end-date'] = test_data['end-date'] + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate the response status code + assert response.status_code == test_data['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(test_data['statusCode']), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_workflow_runs_invalid_auth(api_client, scenario_case): + """ + Test the GET /insights/{project-slug}/workflows/{workflow-name} endpoint with invalid authentication. + + This test checks for proper handling of invalid authentication tokens. + """ + # Override default test data with scenario-specific data + test_data = scenario_case + + # Construct the endpoint path + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}" + + # Prepare query parameters + params = {} + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + if 'start-date' in test_data: + params['start-date'] = test_data['start-date'] + if 'end-date' in test_data: + params['end-date'] = test_data['end-date'] + + # Make the API request with invalid auth + invalid_auth = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=invalid_auth, params=params) + + # Validate the response status code + assert response.status_code != 200, "Expected failure with invalid authentication" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_jobs_get.py b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_jobs_get.py new file mode 100644 index 00000000..f9f2543d --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_jobs_get.py @@ -0,0 +1,119 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/workflows/{workflow-name}/jobs_get for http method type GET +# RoostTestHash=0b14551fdb +# +# + +# ********RoostGPT******** +""" +Test suite for the CircleCI Insights API. + +This suite tests the /insights/{project-slug}/workflows/{workflow-name}/jobs endpoint. +It covers various scenarios including successful responses, authentication errors, and +response schema validation. + +Setup: +- Ensure the config.yml file is correctly set up with the necessary API host and authentication details. +- Place the insights_project-slug_workflows_workflow-name_jobs.json file in the same directory as this test file. + +Run the tests using pytest: +$ pytest test_insights_api.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +API_SPEC_PATH = 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_project-slug_workflows_workflow-name_jobs.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_workflow_job_metrics(api_client, config_test_data, scenario_case): + """ + Test the /insights/{project-slug}/workflows/{workflow-name}/jobs endpoint for various scenarios. + """ + # Override default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}/jobs" + + # Prepare query parameters + params = { + "page-token": test_data.get("page-token"), + "all-branches": test_data.get("all-branches"), + "branch": test_data.get("branch"), + "reporting-window": test_data.get("reporting-window"), + "job-name": test_data.get("job-name"), + } + + # Remove None values from params + params = {k: v for k, v in params.items() if v is not None} + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate response status code + assert response.status_code == test_data['statusCode'], f"Expected {test_data['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_workflow_job_metrics_invalid_auth(api_client, scenario_case): + """ + Test the /insights/{project-slug}/workflows/{workflow-name}/jobs endpoint with invalid authentication. + """ + # Override default test data with scenario-specific data + test_data = {**scenario_case} + + # Construct endpoint path + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}/jobs" + + # Prepare query parameters + params = { + "page-token": test_data.get("page-token"), + "all-branches": test_data.get("all-branches"), + "branch": test_data.get("branch"), + "reporting-window": test_data.get("reporting-window"), + "job-name": test_data.get("job-name"), + } + + # Remove None values from params + params = {k: v for k, v in params.items() if v is not None} + + # Make the API request with invalid auth + invalid_auth = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=invalid_auth, params=params) + + # Validate response status code for invalid auth + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema for error + validation_result = validator.validate_schema_by_response( + endpoint=f"/{endpoint}", + method='GET', + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_summary_get.py b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_summary_get.py new file mode 100644 index 00000000..72591fcf --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_summary_get.py @@ -0,0 +1,100 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/workflows/{workflow-name}/summary_get for http method type GET +# RoostTestHash=b2014120ff +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI Insights API. + +This test suite covers the `/insights/{project-slug}/workflows/{workflow-name}/summary` endpoint. +It includes tests for successful responses, error handling, and security schema validation. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory as this test file. +- Ensure `config.yml` is present in the same directory with the correct API host and authentication details. +- The test data is loaded from `insights_project-slug_workflows_workflow-name_summ.json`. + +Run the tests using the command: + pytest test_insights_api.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'insights_project-slug_workflows_workflow-name_summ.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=[str(i) for i in range(len(_ENDPOINT_DATA))]) +def test_get_workflow_summary(api_client, config_test_data, scenario_case): + """ + Test the GET /insights/{project-slug}/workflows/{workflow-name}/summary endpoint. + + This test checks for successful responses and validates the response schema. + """ + # Override config test data with scenario specific test data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint URL + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}/summary" + + # Prepare query parameters + params = {} + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + if 'branch' in test_data: + params['branch'] = test_data['branch'] + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate the response status code + assert response.status_code == test_data['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=[str(i) for i in range(len(_ENDPOINT_DATA))]) +def test_get_workflow_summary_invalid_auth(api_client, scenario_case): + """ + Test the GET /insights/{project-slug}/workflows/{workflow-name}/summary endpoint with invalid authentication. + + This test checks for error responses when invalid authentication is provided. + """ + # Override config test data with scenario specific test data + test_data = scenario_case + + # Construct the endpoint URL + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}/summary" + + # Prepare query parameters + params = {} + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + if 'branch' in test_data: + params['branch'] = test_data['branch'] + + # Make the API request with invalid auth + invalid_auth = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=invalid_auth, params=params) + + # Validate the response status code is not 2xx + assert response.status_code != 200, f"Unexpected success with invalid auth: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_test-metrics_get.py b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_test-metrics_get.py new file mode 100644 index 00000000..6c206b93 --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_project-slug_workflows_workflow-name_test-metrics_get.py @@ -0,0 +1,98 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/{project-slug}/workflows/{workflow-name}/test-metrics_get for http method type GET +# RoostTestHash=4d63ad4d9a +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI Insights API. + +This suite tests the `/insights/{project-slug}/workflows/{workflow-name}/test-metrics` endpoint. +Ensure that the `config.yml` file is correctly set up with the necessary API host and authentication details. + +To run the tests, use the following command: +pytest test_insights_api.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +API_SPEC_PATH = 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_ENDPOINT_DATA_PATH = _here / 'insights_project-slug_workflows_workflow-name_test.json' +with open(_ENDPOINT_DATA_PATH, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_TEST_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_workflow_test_metrics(api_client, config_test_data, scenario_case): + """ + Test the retrieval of test metrics for a project's workflows. + """ + # Override default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}/test-metrics" + + # Prepare query parameters + params = {} + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate response status code + assert response.status_code == test_data['statusCode'], f"Expected {test_data['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(test_data['statusCode']), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_workflow_test_metrics_invalid_auth(api_client, scenario_case): + """ + Test the retrieval of test metrics with invalid authentication. + """ + # Override default test data with scenario-specific data + test_data = scenario_case + + # Construct endpoint path + endpoint = f"insights/{test_data['project-slug']}/workflows/{test_data['workflow-name']}/test-metrics" + + # Prepare query parameters + params = {} + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'all-branches' in test_data: + params['all-branches'] = test_data['all-branches'] + + # Make the API request with invalid auth + response = api_client.session.get( + f"{api_client.host}/{endpoint}", + headers={'Authorization': 'Bearer invalid_token'}, + params=params + ) + + # Validate response status code for unauthorized access + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema for error + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" diff --git a/tests/CIRCLECI_API/test_insights_time-series_project-slug_workflows_workflow-name_jobs_get.py b/tests/CIRCLECI_API/test_insights_time-series_project-slug_workflows_workflow-name_jobs_get.py new file mode 100644 index 00000000..1d579144 --- /dev/null +++ b/tests/CIRCLECI_API/test_insights_time-series_project-slug_workflows_workflow-name_jobs_get.py @@ -0,0 +1,103 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /insights/time-series/{project-slug}/workflows/{workflow-name}/jobs_get for http method type GET +# RoostTestHash=3f5fbf9535 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI Insights API. + +This test suite validates the /insights/time-series/{project-slug}/workflows/{workflow-name}/jobs endpoint. +It uses pytest fixtures and parameterized tests to ensure comprehensive coverage of the API's functionality. + +Instructions: +- Ensure the `conftest.py` and `validator.py` files are in the same directory as this test file. +- Place the `config.yml` file in the same directory to provide necessary configuration. +- Run the tests using the pytest command. + +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator +import json + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'insights_time-series_project-slug_workflows_workfl.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_timeseries(api_client, config_test_data, scenario_case): + """ + Test the GET /insights/time-series/{project-slug}/workflows/{workflow-name}/jobs endpoint. + + This test checks for successful responses and validates the response schema. + """ + + # Prepare endpoint and parameters + project_slug = scenario_case.get("project-slug", config_test_data['project-slug']) + workflow_name = scenario_case.get("workflow-name", config_test_data['workflow-name']) + endpoint = f"/insights/time-series/{project_slug}/workflows/{workflow_name}/jobs" + + params = {} + if "branch" in scenario_case: + params["branch"] = scenario_case["branch"] + if "granularity" in scenario_case: + params["granularity"] = scenario_case["granularity"] + if "start-date" in scenario_case: + params["start-date"] = scenario_case["start-date"] + if "end-date" in scenario_case: + params["end-date"] = scenario_case["end-date"] + + # Make API request + response = api_client.get(endpoint, params=params) + + # Validate response status code + expected_status_code = scenario_case["statusCode"] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_timeseries_invalid_auth(api_client, scenario_case): + """ + Test the GET /insights/time-series/{project-slug}/workflows/{workflow-name}/jobs endpoint with invalid authentication. + + This test checks for error responses when invalid authentication is provided. + """ + + # Prepare endpoint and parameters + project_slug = scenario_case.get("project-slug", "invalid-project") + workflow_name = scenario_case.get("workflow-name", "invalid-workflow") + endpoint = f"/insights/time-series/{project_slug}/workflows/{workflow_name}/jobs" + + # Make API request with invalid auth + response = api_client.get(endpoint, headers={"Authorization": "Bearer invalid_token"}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_jobs_job-id_cancel_post.py b/tests/CIRCLECI_API/test_jobs_job-id_cancel_post.py new file mode 100644 index 00000000..81553c65 --- /dev/null +++ b/tests/CIRCLECI_API/test_jobs_job-id_cancel_post.py @@ -0,0 +1,103 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /jobs/{job-id}/cancel_post for http method type POST +# RoostTestHash=0c044095a3 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /jobs/{job-id}/cancel + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `config.yml` in the same directory with appropriate configurations. +- Ensure `jobs_job-id_cancel.json` is in the same directory for test data. + +Run the tests using: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +TEST_DATA_FILENAME = 'jobs_job-id_cancel.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_job_by_job_id(api_client, config_test_data, scenario_case): + """ + Test the /jobs/{job-id}/cancel endpoint with various scenarios. + """ + job_id = scenario_case.get("job-id", config_test_data['job-id']) + expected_status_code = scenario_case['statusCode'] + + # Construct the endpoint + endpoint = f"/jobs/{job_id}/cancel" + + # Validate request schema + request_data = {} + validator.validate_json(request_data, "MessageResponse") + + # Make the API request + response = api_client.post(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, ( + f"Expected status code {expected_status_code}, got {response.status_code}" + ) + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'POST', str(response.status_code), response + ) + assert validation_result['valid'], ( + f"Response validation failed: {validation_result.get('message', '')}" + ) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_job_by_job_id_invalid_auth(api_client, scenario_case): + """ + Test the /jobs/{job-id}/cancel endpoint with invalid authentication. + """ + job_id = scenario_case.get("job-id", "invalid-job-id") + expected_status_code = 401 # Unauthorized + + # Construct the endpoint + endpoint = f"/jobs/{job_id}/cancel" + + # Make the API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.post(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == expected_status_code, ( + f"Expected status code {expected_status_code}, got {response.status_code}" + ) + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'POST', str(response.status_code), response + ) + assert validation_result['valid'], ( + f"Response validation failed: {validation_result.get('message', '')}" + ) diff --git a/tests/CIRCLECI_API/test_me_collaborations_get.py b/tests/CIRCLECI_API/test_me_collaborations_get.py new file mode 100644 index 00000000..f4db4d98 --- /dev/null +++ b/tests/CIRCLECI_API/test_me_collaborations_get.py @@ -0,0 +1,97 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /me/collaborations_get for http method type GET +# RoostTestHash=cc75a4293b +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /me/collaborations endpoint. + +This suite tests the endpoint for various scenarios including successful responses, +authentication errors, and schema validation. The tests are parameterized using data +from the `me_collaborations.json` file. + +Setup: +- Ensure `config.yml` is properly configured with the API host and authentication details. +- Place `me_collaborations.json` in the same directory as this test file. + +Execution: +- Run the tests using `pytest` command in the terminal. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +swagger_validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'me_collaborations.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_collaborations(api_client, scenario_case): + """ + Test the /me/collaborations endpoint for various scenarios. + + This test checks for successful responses, schema validation, and error handling. + """ + endpoint = "/me/collaborations" + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + # Make the API request + response = api_client.get(endpoint, headers=headers) + + # Validate the response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint, 'GET', str(response.status_code), response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks for successful responses + if response.status_code == 200: + response_data = response.json() + for item in response_data: + assert 'id' in item, "Missing 'id' in response item" + assert 'vcs-type' in item, "Missing 'vcs-type' in response item" + assert 'name' in item, "Missing 'name' in response item" + assert 'avatar_url' in item, "Missing 'avatar_url' in response item" + assert 'slug' in item, "Missing 'slug' in response item" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_collaborations_invalid_auth(api_client, scenario_case): + """ + Test the /me/collaborations endpoint with invalid authentication. + + This test checks for proper handling of invalid authentication scenarios. + """ + endpoint = "/me/collaborations" + headers = {'Authorization': 'Bearer invalid_token'} + + # Make the API request + response = api_client.get(endpoint, headers=headers) + + # Validate the response status code + assert response.status_code != 200, "Expected authentication error, but got success" + + # Validate the response schema for error + validation_result = swagger_validator.validate_schema_by_response( + endpoint, 'GET', 'default', response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_me_get.py b/tests/CIRCLECI_API/test_me_get.py new file mode 100644 index 00000000..2ad524e6 --- /dev/null +++ b/tests/CIRCLECI_API/test_me_get.py @@ -0,0 +1,99 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /me_get for http method type GET +# RoostTestHash=e56f807845 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /me endpoint of the API. + +This suite tests the /me endpoint for various scenarios including successful responses, +authentication errors, and schema validation. It uses pytest fixtures and parameterized +tests to ensure comprehensive coverage. + +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as `conftest.py`, `validator.py`, and `me.json`. +- Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'me.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_me_endpoint(api_client, scenario_case, config_test_data): + """ + Test the /me endpoint for various scenarios. + + This test checks the response of the /me endpoint for different scenarios + defined in the test data. It validates the response status code and schema. + """ + # Override default test data with scenario specific data + test_data = {**config_test_data, **scenario_case} + + # Make the API request + try: + response = api_client.get('/me') + except Exception as e: + pytest.fail(f"API request failed: {e}") + + # Validate response status code + assert response.status_code == test_data['statusCode'], \ + f"Expected status code {test_data['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + '/me', 'GET', str(response.status_code), response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks for successful response + if response.status_code == 200: + response_data = response.json() + assert response_data['avatar_url'] == test_data['avatar_url'], "Avatar URL mismatch" + assert response_data['id'] == test_data['id'], "ID mismatch" + assert response_data['login'] == test_data['login'], "Login mismatch" + assert response_data['name'] == test_data['name'], "Name mismatch" + +@pytest.mark.parametrize("auth_header", [None, "InvalidToken"]) +def test_get_me_endpoint_auth_errors(api_client, auth_header): + """ + Test the /me endpoint for authentication errors. + + This test checks the response of the /me endpoint when authentication is missing + or invalid. It expects an error response with a non-200 status code. + """ + headers = {} + if auth_header: + headers['Authorization'] = f"Bearer {auth_header}" + + response = api_client.get('/me', headers=headers) + + # Validate response status code is not 200 + assert response.status_code != 200, "Expected non-200 status code for auth errors" + + # Validate response schema for error + validation_result = validator.validate_schema_by_response( + '/me', 'GET', 'default', response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_delete.py b/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_delete.py new file mode 100644 index 00000000..98e5ffcb --- /dev/null +++ b/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_delete.py @@ -0,0 +1,92 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /org/{orgID}/oidc-custom-claims_delete for http method type DELETE +# RoostTestHash=e943c1acb7 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'org_orgID_oidc-custom-claims.json' +with open(_endpoint_data_path, 'r') as file: + _ENDPOINT_DATA = json.load(file) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_org_oidc_custom_claims(api_client, config_test_data, scenario_case): + """ + Test the DELETE /org/{orgID}/oidc-custom-claims endpoint. + """ + org_id = scenario_case.get('orgID', config_test_data['orgID']) + claims = scenario_case.get('claims') + expected_status_code = scenario_case['statusCode'] + + # Construct the endpoint + endpoint = f"/org/{org_id}/oidc-custom-claims?claims={claims}" + + # Validate request schema + request_data = { + "orgID": org_id, + "claims": claims + } + validator.validate_json(request_data, "DeleteOrgClaims") + + # Make the API request + response = api_client.delete(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + + # Additional assertions based on status code + if expected_status_code == 200: + response_data = response.json() + assert 'org_id' in response_data, "Response missing 'org_id'" + elif expected_status_code == 400: + response_data = response.json() + assert 'error' in response_data, "Response missing 'error'" + elif expected_status_code == 403: + response_data = response.json() + assert 'error' in response_data, "Response missing 'error'" + elif expected_status_code == 500: + response_data = response.json() + assert 'error' in response_data, "Response missing 'error'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_org_oidc_custom_claims_invalid_auth(api_client, scenario_case): + """ + Test the DELETE /org/{orgID}/oidc-custom-claims endpoint with invalid authentication. + """ + org_id = scenario_case.get('orgID') + claims = scenario_case.get('claims') + + # Construct the endpoint + endpoint = f"/org/{org_id}/oidc-custom-claims?claims={claims}" + + # Make the API request with invalid auth + response = api_client.delete(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 403, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', '403', response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_get.py b/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_get.py new file mode 100644 index 00000000..31caee54 --- /dev/null +++ b/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_get.py @@ -0,0 +1,82 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /org/{orgID}/oidc-custom-claims_get for http method type GET +# RoostTestHash=ebd41bbba2 +# +# + +# ********RoostGPT******** +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'org_orgID_oidc-custom-claims.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_org_oidc_custom_claims(api_client, scenario_case, config_test_data): + """ + Test the /org/{orgID}/oidc-custom-claims endpoint for various scenarios. + """ + orgID = scenario_case.get('orgID', config_test_data['orgID']) + endpoint = f"/org/{orgID}/oidc-custom-claims" + expected_status_code = scenario_case['statusCode'] + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks based on scenario + if expected_status_code == 200: + response_data = response.json() + assert 'org_id' in response_data, "Response missing 'org_id'" + if 'audience' in scenario_case: + assert response_data['audience'] == scenario_case['audience'], "Mismatch in 'audience'" + if 'project_id' in scenario_case: + assert response_data['project_id'] == scenario_case['project_id'], "Mismatch in 'project_id'" + elif expected_status_code == 400: + assert 'error' in response.json(), "Error message expected in 400 response" + elif expected_status_code == 403: + assert 'error' in response.json(), "Error message expected in 403 response" + elif expected_status_code == 500: + assert 'error' in response.json(), "Error message expected in 500 response" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_org_oidc_custom_claims_invalid_auth(api_client, scenario_case): + """ + Test the /org/{orgID}/oidc-custom-claims endpoint with invalid authentication. + """ + orgID = scenario_case.get('orgID', 'invalid-org-id') + endpoint = f"/org/{orgID}/oidc-custom-claims" + headers = {'Authorization': 'Bearer invalid_token'} + + # Make the API request + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 403, f"Expected 403, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '403', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_patch.py b/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_patch.py new file mode 100644 index 00000000..718aef01 --- /dev/null +++ b/tests/CIRCLECI_API/test_org_orgID_oidc-custom-claims_patch.py @@ -0,0 +1,123 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /org/{orgID}/oidc-custom-claims_patch for http method type PATCH +# RoostTestHash=59465742a7 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /org/{orgID}/oidc-custom-claims. + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place this test file in the same directory as the conftest.py and validator.py files. +3. Ensure the config.yml file is correctly set up with the necessary API host and authentication details. +4. Run the tests using the command: pytest .py + +This test suite covers: +- Successful and unsuccessful PATCH requests to the endpoint. +- Validation of request and response schemas using SwaggerSchemaValidator. +- Various authentication scenarios. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'org_orgID_oidc-custom-claims.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_patch_org_oidc_custom_claims(api_client, config_test_data, scenario_case): + """ + Test PATCH /org/{orgID}/oidc-custom-claims endpoint with various scenarios. + """ + orgID = scenario_case.get("orgID", config_test_data['orgID']) + endpoint = f"/org/{orgID}/oidc-custom-claims" + headers = {'Content-Type': 'application/json'} + + # Prepare request body + request_body = {} + if 'audience' in scenario_case: + request_body['audience'] = scenario_case['audience'] + if 'ttl' in scenario_case: + request_body['ttl'] = scenario_case['ttl'] + + # Validate request schema + validator.validate_json(request_body, 'PatchOrgClaimsRequest') + + # Make API request + response = api_client.patch(endpoint, headers=headers, json=request_body) + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'PATCH', str(scenario_case['statusCode']), response + ) + assert validation_result['valid'], validation_result.get('message', 'Invalid response schema') + + # Assert response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_patch_org_oidc_custom_claims_invalid_auth(api_client, scenario_case): + """ + Test PATCH /org/{orgID}/oidc-custom-claims endpoint with invalid authentication. + """ + orgID = scenario_case.get("orgID", "invalid-org-id") + endpoint = f"/org/{orgID}/oidc-custom-claims" + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer invalid_token'} + + # Prepare request body + request_body = {} + if 'audience' in scenario_case: + request_body['audience'] = scenario_case['audience'] + if 'ttl' in scenario_case: + request_body['ttl'] = scenario_case['ttl'] + + # Make API request + response = api_client.patch(endpoint, headers=headers, json=request_body) + + # Assert response status code for invalid auth + assert response.status_code == 403, f"Expected 403, got {response.status_code}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_patch_org_oidc_custom_claims_missing_auth(api_client, scenario_case): + """ + Test PATCH /org/{orgID}/oidc-custom-claims endpoint with missing authentication. + """ + orgID = scenario_case.get("orgID", "invalid-org-id") + endpoint = f"/org/{orgID}/oidc-custom-claims" + headers = {'Content-Type': 'application/json'} + + # Prepare request body + request_body = {} + if 'audience' in scenario_case: + request_body['audience'] = scenario_case['audience'] + if 'ttl' in scenario_case: + request_body['ttl'] = scenario_case['ttl'] + + # Make API request + response = api_client.patch(endpoint, headers=headers, json=request_body) + + # Assert response status code for missing auth + assert response.status_code == 403, f"Expected 403, got {response.status_code}" diff --git a/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_delete.py b/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_delete.py new file mode 100644 index 00000000..c4b56dda --- /dev/null +++ b/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_delete.py @@ -0,0 +1,72 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /org/{orgID}/project/{projectID}/oidc-custom-claims_delete for http method type DELETE +# RoostTestHash=8230f59e1e +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'org_orgID_project_projectID_oidc-custom-claims.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_oidc_custom_claims(api_client, config_test_data, scenario_case): + """ + Test DELETE /org/{orgID}/project/{projectID}/oidc-custom-claims endpoint + """ + org_id = scenario_case.get('orgID', config_test_data['orgID']) + project_id = scenario_case.get('projectID', config_test_data['projectID']) + claims = scenario_case.get('claims', '') + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/org/{org_id}/project/{project_id}/oidc-custom-claims?claims={claims}" + + # Validate request schema before sending + request_data = { + "orgID": org_id, + "projectID": project_id, + "claims": claims + } + validator.validate_json(request_data, "DeleteProjectClaims") + + # Make the DELETE request + response = api_client.delete(endpoint) + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'DELETE', str(expected_status_code), response + ) + assert validation_result['valid'], validation_result.get('message', '') + + # Assert the expected status code + assert response.status_code == expected_status_code + + # Additional response validation based on status code + if response.status_code == 200: + response_data = response.json() + assert 'org_id' in response_data + assert response_data['org_id'] == org_id + elif response.status_code == 400: + assert 'error' in response.json() + elif response.status_code == 403: + assert 'error' in response.json() + elif response.status_code == 500: + assert 'error' in response.json() diff --git a/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_get.py b/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_get.py new file mode 100644 index 00000000..d1f7d613 --- /dev/null +++ b/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_get.py @@ -0,0 +1,92 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /org/{orgID}/project/{projectID}/oidc-custom-claims_get for http method type GET +# RoostTestHash=ff08783e7f +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'org_orgID_project_projectID_oidc-custom-claims.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_oidc_custom_claims(api_client, config_test_data, scenario_case): + """ + Test the /org/{orgID}/project/{projectID}/oidc-custom-claims endpoint. + """ + # Override default test data with scenario specific data + orgID = scenario_case.get('orgID', config_test_data['orgID']) + projectID = scenario_case.get('projectID', config_test_data['projectID']) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint path + endpoint = f"/org/{orgID}/project/{projectID}/oidc-custom-claims" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', str(expected_status_code), response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks based on status code + if expected_status_code == 200: + # Validate specific fields in the response + response_data = response.json() + assert 'org_id' in response_data, "Missing 'org_id' in response" + assert response_data['org_id'] == orgID, "Mismatch in 'org_id'" + elif expected_status_code == 400: + response_data = response.json() + assert 'error' in response_data, "Missing 'error' in response" + elif expected_status_code == 403: + response_data = response.json() + assert 'error' in response_data, "Missing 'error' in response" + elif expected_status_code == 500: + response_data = response.json() + assert 'error' in response_data, "Missing 'error' in response" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_oidc_custom_claims_invalid_auth(api_client, scenario_case): + """ + Test the /org/{orgID}/project/{projectID}/oidc-custom-claims endpoint with invalid auth. + """ + orgID = scenario_case.get('orgID') + projectID = scenario_case.get('projectID') + + # Construct endpoint path + endpoint = f"/org/{orgID}/project/{projectID}/oidc-custom-claims" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 403, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', '403', response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_patch.py b/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_patch.py new file mode 100644 index 00000000..b3eb2190 --- /dev/null +++ b/tests/CIRCLECI_API/test_org_orgID_project_projectID_oidc-custom-claims_patch.py @@ -0,0 +1,72 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /org/{orgID}/project/{projectID}/oidc-custom-claims_patch for http method type PATCH +# RoostTestHash=fdcb8dc416 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'org_orgID_project_projectID_oidc-custom-claims.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_patch_oidc_custom_claims(api_client, config_test_data, scenario_case): + """ + Test PATCH /org/{orgID}/project/{projectID}/oidc-custom-claims + """ + # Setup + org_id = scenario_case.get('orgID', config_test_data['orgID']) + project_id = scenario_case.get('projectID', config_test_data['projectID']) + endpoint = f"/org/{org_id}/project/{project_id}/oidc-custom-claims" + headers = {'Content-Type': 'application/json'} + + # Request body + request_body = {} + if 'audience' in scenario_case: + request_body['audience'] = scenario_case['audience'] + if 'ttl' in scenario_case: + request_body['ttl'] = scenario_case['ttl'] + + # Validate request schema + if request_body: + validation_result = validator.validate_json(request_body, 'PatchProjectClaimsRequest') + assert validation_result['valid'], f"Request validation failed: {validation_result}" + + # Execute API call + response = api_client.patch(endpoint, headers=headers, json=request_body) + + # Validate response schema + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + validation_result = validator.validate_schema_by_response(endpoint, 'PATCH', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result}" + + # Additional assertions based on status code + if response.status_code == 200: + response_data = response.json() + assert response_data['org_id'] == org_id, "org_id mismatch" + assert response_data['project_id'] == project_id, "project_id mismatch" + elif response.status_code == 400: + assert 'error' in response.json(), "Expected error message in response" + elif response.status_code == 403: + assert 'error' in response.json(), "Expected error message in response" + elif response.status_code == 500: + assert 'error' in response.json(), "Expected error message in response" diff --git a/tests/CIRCLECI_API/test_organization_org-slug-or-id_delete.py b/tests/CIRCLECI_API/test_organization_org-slug-or-id_delete.py new file mode 100644 index 00000000..57c390ab --- /dev/null +++ b/tests/CIRCLECI_API/test_organization_org-slug-or-id_delete.py @@ -0,0 +1,107 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organization/{org-slug-or-id}_delete for http method type DELETE +# RoostTestHash=5287fa5aeb +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the DELETE /organization/{org-slug-or-id} endpoint. + +Setup: +- Ensure `conftest.py` is in the same directory to provide necessary fixtures. +- Ensure `organization_org-slug-or-id.json` is in the same directory for test data. +- Ensure `validator.py` is available for schema validation. + +Run the tests using pytest in the terminal: +$ pytest -v +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organization_org-slug-or-id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i, _ in enumerate(_ENDPOINT_DATA)] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_organization(api_client, config_test_data, scenario_case): + """ + Test DELETE /organization/{org-slug-or-id} endpoint with various scenarios. + """ + # Prepare test data + org_slug_or_id = scenario_case.get("org-slug-or-id", config_test_data["org-slug-or-id"]) + expected_status_code = scenario_case["statusCode"] + + # Construct endpoint + endpoint = f"/organization/{org_slug_or_id}" + + # Perform DELETE request + response = api_client.delete(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_organization_invalid_auth(api_client, scenario_case): + """ + Test DELETE /organization/{org-slug-or-id} endpoint with invalid authentication. + """ + # Prepare test data + org_slug_or_id = scenario_case.get("org-slug-or-id", "invalid-org-id") + expected_status_code = 401 # Assuming 401 for invalid auth + + # Construct endpoint + endpoint = f"/organization/{org_slug_or_id}" + + # Perform DELETE request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.make_request(endpoint, method='DELETE', headers=headers) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_organization_missing_auth(api_client, scenario_case): + """ + Test DELETE /organization/{org-slug-or-id} endpoint with missing authentication. + """ + # Prepare test data + org_slug_or_id = scenario_case.get("org-slug-or-id", "missing-auth-org-id") + expected_status_code = 401 # Assuming 401 for missing auth + + # Construct endpoint + endpoint = f"/organization/{org_slug-or-id}" + + # Perform DELETE request without token + response = api_client.make_request(endpoint, method='DELETE', headers={}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_organization_org-slug-or-id_project_post.py b/tests/CIRCLECI_API/test_organization_org-slug-or-id_project_post.py new file mode 100644 index 00000000..0d6620a9 --- /dev/null +++ b/tests/CIRCLECI_API/test_organization_org-slug-or-id_project_post.py @@ -0,0 +1,80 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organization/{org-slug-or-id}/project_post for http method type POST +# RoostTestHash=3422ce79e2 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'organization_org-slug-or-id_project.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_project(api_client, config_test_data, scenario_case): + """ + Test creating a new project in an organization. + """ + org_slug_or_id = scenario_case.get("org-slug-or-id", config_test_data['org-slug-or-id']) + name = scenario_case.get("name", config_test_data['name']) + expected_status_code = scenario_case.get("statusCode", 200) + + endpoint = f"organization/{org_slug_or_id}/project" + payload = {"name": name} + + # Validate request payload + request_validation = validator.validate_json(payload, "Project") + assert request_validation['valid'], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=payload) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_project_invalid_auth(api_client, scenario_case): + """ + Test creating a new project with invalid authentication. + """ + org_slug_or_id = scenario_case.get("org-slug-or-id", "invalid-org") + name = scenario_case.get("name", "invalid-name") + expected_status_code = 401 + + endpoint = f"organization/{org_slug_or_id}/project" + payload = {"name": name} + + # Make API request with invalid token + response = api_client.post(endpoint, json=payload, headers={"Authorization": "Bearer invalid_token"}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_allow-list-entry-id_delete.py b/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_allow-list-entry-id_delete.py new file mode 100644 index 00000000..6771d480 --- /dev/null +++ b/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_allow-list-entry-id_delete.py @@ -0,0 +1,70 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organization/{org-slug-or-id}/url-orb-allow-list/{allow-list-entry-id}_delete for http method type DELETE +# RoostTestHash=65dd53e86c +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'organization_org-slug-or-id_url-orb-allow-list_all.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_remove_url_orb_allow_list_entry(api_client, config_test_data, scenario_case): + """ + Test the removal of an entry from the org's URL orb allow-list. + """ + org_slug_or_id = scenario_case.get('org-slug-or-id', config_test_data['org-slug-or-id']) + allow_list_entry_id = scenario_case.get('allow-list-entry-id', config_test_data['allow-list-entry-id']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/organization/{org_slug_or_id}/url-orb-allow-list/{allow_list_entry_id}" + + # Validate request schema before sending + request_data = {} + validator.validate_json(request_data, 'RemoveURLOrbAllowListEntryRequest') + + # Make the DELETE request + response = api_client.delete(endpoint) + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" + + # Assert the expected status code + if expected_status_code == 'default': + assert not (200 <= response.status_code < 300), "Unexpected success status code for default case" + else: + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Additional assertions based on scenario + if response.status_code == 200: + response_data = response.json() + assert 'id' in response_data, "Response missing 'id'" + assert 'message' in response_data, "Response missing 'message'" + elif response.status_code != 200: + response_data = response.json() + assert 'message' in response_data, "Error response missing 'message'" diff --git a/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_get.py b/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_get.py new file mode 100644 index 00000000..428db28a --- /dev/null +++ b/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_get.py @@ -0,0 +1,98 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organization/{org-slug-or-id}/url-orb-allow-list_get for http method type GET +# RoostTestHash=1dc9b8422f +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI API endpoint: +GET /organization/{org-slug-or-id}/url-orb-allow-list + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `organization_org-slug-or-id_url-orb-allow-list.json` in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. + +Run the tests using pytest: +$ pytest test_api.py +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +API_SPEC_PATH = 'api.json' +swagger_validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'organization_org-slug-or-id_url-orb-allow-list.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_url_orb_allow_list(api_client, config_test_data, scenario_case): + """ + Test the GET /organization/{org-slug-or-id}/url-orb-allow-list endpoint. + """ + org_slug_or_id = scenario_case.get('org-slug-or-id', config_test_data['org-slug-or-id']) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint + endpoint = f"/organization/{org_slug_or_id}/url-orb-allow-list" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + if expected_status_code == "default": + assert not (200 <= response.status_code < 300), "Unexpected success status code" + else: + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint=endpoint, + method='GET', + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_url_orb_allow_list_invalid_auth(api_client, scenario_case): + """ + Test the GET /organization/{org-slug-or-id}/url-orb-allow-list endpoint with invalid authentication. + """ + org_slug_or_id = scenario_case.get('org-slug-or-id', 'invalid-org-id') + endpoint = f"/organization/{org_slug_or_id}/url-orb-allow-list" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code for unauthorized access + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint=endpoint, + method='GET', + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" diff --git a/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_post.py b/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_post.py new file mode 100644 index 00000000..0f7df6dd --- /dev/null +++ b/tests/CIRCLECI_API/test_organization_org-slug-or-id_url-orb-allow-list_post.py @@ -0,0 +1,94 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organization/{org-slug-or-id}/url-orb-allow-list_post for http method type POST +# RoostTestHash=11ba21864e +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organization_org-slug-or-id_url-orb-allow-list.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['org-slug-or-id']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_url_orb_allow_list_entry(api_client, config_test_data, scenario_case): + """ + Test the creation of a URL Orb allow-list entry. + """ + endpoint = f"organization/{scenario_case['org-slug-or-id']}/url-orb-allow-list" + method = 'POST' + headers = {'Content-Type': 'application/json'} + + # Prepare request body + request_body = { + "name": scenario_case.get("name", config_test_data['name']), + "prefix": scenario_case.get("prefix", config_test_data.get('prefix', {})), + "auth": scenario_case.get("auth", config_test_data.get('auth', '')) + } + + # Validate request schema + request_validation = validator.validate_json(request_body, 'RequestBodySchemaName') + assert request_validation['valid'], f"Request validation failed: {request_validation['message']}" + + # Make API request + response = api_client.post(endpoint, json=request_body, headers=headers) + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, method, str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" + + # Assert response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Additional assertions based on status code + if response.status_code == 200: + response_data = response.json() + assert 'id' in response_data, "Response missing 'id'" + assert 'message' in response_data, "Response missing 'message'" + else: + response_data = response.json() + assert 'message' in response_data, "Error response missing 'message'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_url_orb_allow_list_entry_invalid_auth(api_client, scenario_case): + """ + Test the creation of a URL Orb allow-list entry with invalid authentication. + """ + endpoint = f"organization/{scenario_case['org-slug-or-id']}/url-orb-allow-list" + method = 'POST' + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer invalid_token'} + + # Prepare request body + request_body = { + "name": scenario_case.get("name", "InvalidAuthTest"), + "prefix": scenario_case.get("prefix", {}), + "auth": scenario_case.get("auth", '') + } + + # Make API request + response = api_client.post(endpoint, json=request_body, headers=headers) + + # Assert response status code for invalid auth + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, method, str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" diff --git a/tests/CIRCLECI_API/test_organization_post.py b/tests/CIRCLECI_API/test_organization_post.py new file mode 100644 index 00000000..a96220a1 --- /dev/null +++ b/tests/CIRCLECI_API/test_organization_post.py @@ -0,0 +1,111 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organization_post for http method type POST +# RoostTestHash=c2eca3b719 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI API - Organization endpoint. + +This test suite validates the creation of organizations via the CircleCI API. +It uses pytest fixtures and parameterized tests to ensure comprehensive coverage +of the API's functionality, including authentication, request validation, and +response validation. + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place this test file in the same directory as your conftest.py and validator.py. +3. Run the tests using the command: pytest .py + +Dependencies: +- pytest +- requests +- jsonschema +- yaml +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Constants +TEST_DATA_FILENAME = 'organization.json' +API_SPEC_PATH = 'api.json' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +# Initialize SwaggerSchemaValidator +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_organization(api_client, config_test_data, scenario_case): + """ + Test the creation of an organization using the CircleCI API. + + This test covers: + - Successful creation of an organization + - Validation of response schema + - Handling of different response status codes + """ + # Prepare request data + request_data = { + "name": scenario_case.get("name", config_test_data['name']), + "vcs_type": scenario_case.get("vcs_type", config_test_data['provider']) + } + + # Validate request data against schema + validation_result = validator.validate_json(request_data, "createOrganizationRequest") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post('/organization', json=request_data) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + schema_validation_result = validator.validate_schema_by_response( + '/organization', 'post', str(expected_status_code), response + ) + assert schema_validation_result['valid'], f"Response validation failed: {schema_validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_organization_invalid_auth(api_client, scenario_case): + """ + Test the creation of an organization with invalid authentication. + + This test ensures that the API returns the correct error response when + invalid authentication credentials are used. + """ + # Prepare request data + request_data = { + "name": scenario_case.get("name"), + "vcs_type": scenario_case.get("vcs_type") + } + + # Make API request with invalid auth + invalid_headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.post('/organization', json=request_data, headers=invalid_headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + schema_validation_result = validator.validate_schema_by_response( + '/organization', 'post', 'default', response + ) + assert schema_validation_result['valid'], f"Response validation failed: {schema_validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_organizations_org_id_groups_get.py b/tests/CIRCLECI_API/test_organizations_org_id_groups_get.py new file mode 100644 index 00000000..a1b3aef7 --- /dev/null +++ b/tests/CIRCLECI_API/test_organizations_org_id_groups_get.py @@ -0,0 +1,85 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organizations/{org_id}/groups_get for http method type GET +# RoostTestHash=270c27f81d +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the /organizations/{org_id}/groups endpoint. + +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as the `conftest.py` and `validator.py`. +- Ensure the `organizations_org_id_groups.json` file is in the same directory. +- Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organizations_org_id_groups.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=[str(i) for i in range(len(_ENDPOINT_DATA))]) +def test_get_organization_groups(api_client, config_test_data, scenario_case): + """ + Test the GET /organizations/{org_id}/groups endpoint with various scenarios. + """ + org_id = config_test_data['org_id'] + endpoint = f"organizations/{org_id}/groups" + params = {} + + # Add parameters from scenario case if they exist + if 'limit' in scenario_case: + params['limit'] = scenario_case['limit'] + if 'page-token' in scenario_case: + params['page-token'] = scenario_case['page-token'] + + # Validate request schema + validator.validate_json(params, 'getOrganizationGroupsRequest') + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Response schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("auth_scenario", ['valid', 'invalid', 'missing']) +def test_authentication_scenarios(api_client, config_test_data, auth_scenario): + """ + Test authentication scenarios for the GET /organizations/{org_id}/groups endpoint. + """ + org_id = config_test_data['org_id'] + endpoint = f"organizations/{org_id}/groups" + params = {'limit': 10} + + if auth_scenario == 'valid': + response = api_client.get(endpoint, params=params) + assert response.status_code == 200 + elif auth_scenario == 'invalid': + response = api_client.get(endpoint, params=params, headers={'Authorization': 'Bearer invalid_token'}) + assert response.status_code == 403 + elif auth_scenario == 'missing': + response = api_client.get(endpoint, params=params, headers={}) + assert response.status_code == 403 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Response schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_delete.py b/tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_delete.py new file mode 100644 index 00000000..b634f0e6 --- /dev/null +++ b/tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_delete.py @@ -0,0 +1,100 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organizations/{org_id}/groups/{group_id}_delete for http method type DELETE +# RoostTestHash=44b6c6c694 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the DELETE /organizations/{org_id}/groups/{group_id} endpoint. + +This test suite covers: +- Successful deletion of a group. +- Various error scenarios including invalid credentials, insufficient permissions, and not found errors. +- Validation of response schemas using SwaggerSchemaValidator. + +Instructions: +- Ensure the conftest.py and validator.py files are correctly set up in the test environment. +- Place the organizations_org_id_groups_group_id.json file in the same directory as this test file. +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Constants +TEST_DATA_FILENAME = 'organizations_org_id_groups_group_id.json' +API_SPEC_PATH = 'api.json' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +# Initialize SwaggerSchemaValidator +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_group(api_client, config_test_data, scenario_case): + """ + Test DELETE /organizations/{org_id}/groups/{group_id} endpoint. + """ + org_id = config_test_data['org_id'] + group_id = config_test_data['group_id'] + endpoint = f"/organizations/{org_id}/groups/{group_id}" + + # Prepare headers + headers = { + 'Authorization': f"Bearer {api_client.auth['api_key_header']}" + } + + # Make DELETE request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Validate response message + response_data = response.json() + assert response_data['message'] == scenario_case['message'], f"Expected message '{scenario_case['message']}', got '{response_data['message']}'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_group_invalid_auth(api_client, scenario_case): + """ + Test DELETE /organizations/{org_id}/groups/{group_id} endpoint with invalid authentication. + """ + org_id = "invalid_org_id" + group_id = "invalid_group_id" + endpoint = f"/organizations/{org_id}/groups/{group_id}" + + # Prepare headers with invalid token + headers = { + 'Authorization': "Bearer invalid_token" + } + + # Make DELETE request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Validate response message + response_data = response.json() + assert response_data['message'] == "Invalid token provided.", f"Expected message 'Invalid token provided.', got '{response_data['message']}'" diff --git a/tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_get.py b/tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_get.py new file mode 100644 index 00000000..3362b106 --- /dev/null +++ b/tests/CIRCLECI_API/test_organizations_org_id_groups_group_id_get.py @@ -0,0 +1,93 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organizations/{org_id}/groups/{group_id}_get for http method type GET +# RoostTestHash=d575cc0b59 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organizations_org_id_groups_group_id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"case_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_group(api_client, config_test_data, scenario_case): + """ + Test the GET /organizations/{org_id}/groups/{group_id} endpoint. + """ + org_id = config_test_data['org_id'] + group_id = scenario_case['id'] + endpoint = f"organizations/{org_id}/groups/{group_id}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(scenario_case['statusCode']), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional response content validation + if response.status_code == 200: + response_data = response.json() + assert response_data['id'] == scenario_case['id'], "ID mismatch" + assert response_data['name'] == scenario_case['name'], "Name mismatch" + if 'description' in scenario_case: + assert response_data['description'] == scenario_case['description'], "Description mismatch" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_group_invalid_auth(api_client, scenario_case): + """ + Test the GET /organizations/{org_id}/groups/{group_id} endpoint with invalid authentication. + """ + org_id = scenario_case['id'] + group_id = scenario_case['id'] + endpoint = f"organizations/{org_id}/groups/{group_id}" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate the response status code + assert response.status_code == 403, "Expected 403 Forbidden for invalid auth" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '403', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_group_not_found(api_client, scenario_case): + """ + Test the GET /organizations/{org_id}/groups/{group_id} endpoint for a non-existent group. + """ + org_id = scenario_case['id'] + group_id = "non-existent-group-id" + endpoint = f"organizations/{org_id}/groups/{group_id}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == 404, "Expected 404 Not Found for non-existent group" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '404', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_organizations_org_id_groups_post.py b/tests/CIRCLECI_API/test_organizations_org_id_groups_post.py new file mode 100644 index 00000000..c83570b0 --- /dev/null +++ b/tests/CIRCLECI_API/test_organizations_org_id_groups_post.py @@ -0,0 +1,108 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organizations/{org_id}/groups_post for http method type POST +# RoostTestHash=1dfa132267 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load API spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organizations_org_id_groups.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_organization_group(api_client, config_test_data, scenario_case): + """ + Test the creation of organization groups with various scenarios. + """ + # Prepare request data + org_id = config_test_data['org_id'] + endpoint = f"/organizations/{org_id}/groups" + request_data = { + "name": scenario_case.get("name"), + "description": scenario_case.get("description", "") + } + + # Validate request data + validation_result = validator.validate_json(request_data, "CreateGroupRequest") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + response_validation = validator.validate_schema_by_response(endpoint, "post", str(expected_status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("auth_header", [ + {"Authorization": "Bearer invalid_token"}, + {"Authorization": ""} +], ids=["invalid_token", "missing_token"]) +def test_create_organization_group_auth_errors(api_client, config_test_data, auth_header): + """ + Test authentication errors for creating organization groups. + """ + org_id = config_test_data['org_id'] + endpoint = f"/organizations/{org_id}/groups" + request_data = { + "name": "Test Group" + } + + # Validate request data + validation_result = validator.validate_json(request_data, "CreateGroupRequest") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make API request with invalid/missing auth + response = api_client.post(endpoint, json=request_data, headers=auth_header) + + # Validate response + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + response_validation = validator.validate_schema_by_response(endpoint, "post", "401", response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_organization_group_conflict(api_client, config_test_data, scenario_case): + """ + Test conflict scenarios for creating organization groups. + """ + org_id = config_test_data['org_id'] + endpoint = f"/organizations/{org_id}/groups" + request_data = { + "name": scenario_case.get("name"), + "description": scenario_case.get("description", "") + } + + # Validate request data + validation_result = validator.validate_json(request_data, "CreateGroupRequest") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Simulate conflict by creating the same group twice + api_client.post(endpoint, json=request_data) + response = api_client.post(endpoint, json=request_data) + + # Validate response + assert response.status_code == 409, f"Expected 409 Conflict, got {response.status_code}" + + response_validation = validator.validate_schema_by_response(endpoint, "post", "409", response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_post.py b/tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_post.py new file mode 100644 index 00000000..49550e7a --- /dev/null +++ b/tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_post.py @@ -0,0 +1,108 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organizations/{org_id}/usage_export_job_post for http method type POST +# RoostTestHash=6414609995 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organizations_org_id_usage_export_job.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_usage_export(api_client, config_test_data, scenario_case): + """ + Test the /organizations/{org_id}/usage_export_job endpoint for creating a usage export. + """ + org_id = config_test_data['org_id'] + endpoint = f"/organizations/{org_id}/usage_export_job" + + # Prepare request payload + payload = { + "start": scenario_case["start"], + "end": scenario_case["end"] + } + if "shared_org_ids" in scenario_case: + payload["shared_org_ids"] = scenario_case["shared_org_ids"] + + # Validate request payload + validation_result = validator.validate_json(payload, "createUsageExportRequest") + assert validation_result["valid"], f"Request validation failed: {validation_result['message']}" + + # Make API request + response = api_client.post(endpoint, json=payload) + + # Validate response status code + assert response.status_code == scenario_case["statusCode"], f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, "post", str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" + +@pytest.mark.parametrize("auth_scenario", ["valid", "invalid", "missing"]) +def test_authentication(api_client, config_test_data, auth_scenario): + """ + Test authentication scenarios for the /organizations/{org_id}/usage_export_job endpoint. + """ + org_id = config_test_data['org_id'] + endpoint = f"/organizations/{org_id}/usage_export_job" + payload = { + "start": "2023-01-01T00:00:00Z", + "end": "2023-01-31T23:59:59Z" + } + + if auth_scenario == "valid": + response = api_client.post(endpoint, json=payload) + assert response.status_code == 201, "Expected 201 Created for valid authentication" + elif auth_scenario == "invalid": + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.post(f"{api_client.host}/{endpoint.lstrip('/')}", headers=headers, json=payload) + assert response.status_code == 401, "Expected 401 Unauthorized for invalid authentication" + elif auth_scenario == "missing": + headers = {} + response = api_client.session.post(f"{api_client.host}/{endpoint.lstrip('/')}", headers=headers, json=payload) + assert response.status_code == 401, "Expected 401 Unauthorized for missing authentication" + +@pytest.mark.parametrize("error_scenario", ["400", "404", "429", "500"]) +def test_error_responses(api_client, config_test_data, error_scenario): + """ + Test error responses for the /organizations/{org_id}/usage_export_job endpoint. + """ + org_id = config_test_data['org_id'] + endpoint = f"/organizations/{org_id}/usage_export_job" + payload = { + "start": "2023-01-01T00:00:00Z", + "end": "2023-01-31T23:59:59Z" + } + + if error_scenario == "400": + payload["invalid_field"] = "invalid_value" + response = api_client.post(endpoint, json=payload) + assert response.status_code == 400, "Expected 400 Bad Request for invalid payload" + elif error_scenario == "404": + invalid_endpoint = f"/organizations/invalid_org_id/usage_export_job" + response = api_client.post(invalid_endpoint, json=payload) + assert response.status_code == 404, "Expected 404 Not Found for invalid organization" + elif error_scenario == "429": + pytest.skip("Rate limit testing requires specific setup not covered here") + elif error_scenario == "500": + pytest.skip("500 Internal Server Error testing requires specific setup not covered here") diff --git a/tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_usage_export_job_id_get.py b/tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_usage_export_job_id_get.py new file mode 100644 index 00000000..68a45b2a --- /dev/null +++ b/tests/CIRCLECI_API/test_organizations_org_id_usage_export_job_usage_export_job_id_get.py @@ -0,0 +1,73 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /organizations/{org_id}/usage_export_job/{usage_export_job_id}_get for http method type GET +# RoostTestHash=a759f757ba +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /organizations/{org_id}/usage_export_job/{usage_export_job_id} + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Ensure `organizations_org_id_usage_export_job_usage_export.json` is in the same directory. +- Ensure `config.yml` is configured correctly. + +Run the tests using `pytest` command. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'organizations_org_id_usage_export_job_usage_export.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_usage_export(api_client, config_test_data, scenario_case): + """ + Test the GET /organizations/{org_id}/usage_export_job/{usage_export_job_id} endpoint. + """ + # Prepare endpoint and headers + org_id = config_test_data['org_id'] + usage_export_job_id = scenario_case['usage_export_job_id'] + endpoint = f"/organizations/{org_id}/usage_export_job/{usage_export_job_id}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=endpoint, + method='GET', + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional response content validation + if response.status_code == 200: + response_data = response.json() + assert response_data['usage_export_job_id'] == scenario_case['usage_export_job_id'] + assert response_data['state'] == scenario_case['state'] + assert response_data['download_urls'] == scenario_case['download_urls'] + if 'error_reason' in scenario_case: + assert response_data.get('error_reason') == scenario_case['error_reason'] diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_get.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_get.py new file mode 100644 index 00000000..70371d11 --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_get.py @@ -0,0 +1,94 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/decision/{decisionID}_get for http method type GET +# RoostTestHash=72f3fccb7f +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /owner/{ownerID}/context/{context}/decision/{decisionID} + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place this test file, conftest.py, validator.py, and config.yml in the same directory. +3. Run the tests using the command: pytest .py + +This test suite covers: +- Successful response scenarios +- Error response scenarios (400, 401, 403, 404, 500) +- Security schema testing with valid and invalid credentials +- Schema validation using SwaggerSchemaValidator +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load API specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +TEST_DATA_FILENAME = 'owner_ownerID_context_context_decision_decisionID.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as f: + return json.load(f) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_log(api_client, config_test_data, scenario_case): + """ + Test the GET /owner/{ownerID}/context/{context}/decision/{decisionID} endpoint + """ + # Override config_test_data with scenario specific test data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint path + endpoint = f"/owner/{test_data['ownerID']}/context/{test_data['context']}/decision/{test_data['decisionID']}" + + # Validate request schema before sending + validator.validate_json(test_data, 'GetDecisionLog') + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == test_data['statusCode'], f"Expected {test_data['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_log_invalid_auth(api_client, scenario_case): + """ + Test the GET /owner/{ownerID}/context/{context}/decision/{decisionID} endpoint with invalid auth + """ + # Override config_test_data with scenario specific test data + test_data = scenario_case + + # Construct the endpoint path + endpoint = f"/owner/{test_data['ownerID']}/context/{test_data['context']}/decision/{test_data['decisionID']}" + + # Make the API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_policy-bundle_get.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_policy-bundle_get.py new file mode 100644 index 00000000..cd9270aa --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_decisionID_policy-bundle_get.py @@ -0,0 +1,120 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/decision/{decisionID}/policy-bundle_get for http method type GET +# RoostTestHash=855dc1cbc0 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Initialize SwaggerSchemaValidator with the API spec path +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_decision_decisionID_.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle(api_client, config_test_data, scenario_case): + """ + Test the retrieval of policy bundle for a given decision log ID. + """ + # Override config_test_data with scenario specific test data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + endpoint = f"/owner/{test_data['ownerID']}/context/{test_data['context']}/decision/{test_data['decisionID']}/policy-bundle" + + # Validate request schema before sending + request_validation = validator.validate_json(test_data, 'GetDecisionLogPolicyBundle') + assert request_validation['valid'], f"Request validation failed: {request_validation['message']}" + + # Make API request + try: + response = api_client.get(endpoint) + except requests.exceptions.HTTPError as e: + response = e.response + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" + + # Assert status code + assert response.status_code == test_data['statusCode'], f"Expected {test_data['statusCode']}, got {response.status_code}" + + # Additional assertions based on status code + if response.status_code == 200: + # Validate specific fields in successful response + response_json = response.json() + assert 'content' in response_json, "Missing 'content' in response" + assert 'created_at' in response_json, "Missing 'created_at' in response" + assert 'created_by' in response_json, "Missing 'created_by' in response" + assert 'name' in response_json, "Missing 'name' in response" + elif response.status_code in {400, 401, 403, 404, 500}: + # Validate error message in error response + response_json = response.json() + assert 'error' in response_json, "Missing 'error' in response" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle_invalid_auth(api_client, scenario_case): + """ + Test the retrieval of policy bundle with invalid authentication. + """ + # Override config_test_data with scenario specific test data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + endpoint = f"/owner/{test_data['ownerID']}/context/{test_data['context']}/decision/{test_data['decisionID']}/policy-bundle" + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + try: + response = api_client.get(endpoint, headers=headers) + except requests.exceptions.HTTPError as e: + response = e.response + + # Assert status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate error message in response + response_json = response.json() + assert 'error' in response_json, "Missing 'error' in response" + assert response_json['error'] == "Unauthorized", "Unexpected error message" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle_missing_auth(api_client, scenario_case): + """ + Test the retrieval of policy bundle with missing authentication. + """ + # Override config_test_data with scenario specific test data + test_data = {**config_test_data, **scenario_case} + + # Construct endpoint path + endpoint = f"/owner/{test_data['ownerID']}/context/{test_data['context']}/decision/{test_data['decisionID']}/policy-bundle" + + # Make API request without authentication + try: + response = api_client.get(endpoint, headers={}) + except requests.exceptions.HTTPError as e: + response = e.response + + # Assert status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate error message in response + response_json = response.json() + assert 'error' in response_json, "Missing 'error' in response" + assert response_json['error'] == "Unauthorized", "Unexpected error message" diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_get.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_get.py new file mode 100644 index 00000000..354f7cfc --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_get.py @@ -0,0 +1,90 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/decision_get for http method type GET +# RoostTestHash=c6391b06b6 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_decision.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_logs(api_client, config_test_data, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/decision endpoint. + """ + ownerID = scenario_case.get("ownerID", config_test_data["ownerID"]) + context = scenario_case.get("context", config_test_data["context"]) + status = scenario_case.get("status") + after = scenario_case.get("after") + before = scenario_case.get("before") + branch = scenario_case.get("branch") + project_id = scenario_case.get("project_id") + build_number = scenario_case.get("build_number") + offset = scenario_case.get("offset") + expected_status_code = scenario_case["statusCode"] + + # Construct the endpoint path + endpoint = f"/owner/{ownerID}/context/{context}/decision" + params = { + "status": status, + "after": after, + "before": before, + "branch": branch, + "project_id": project_id, + "build_number": build_number, + "offset": offset + } + # Remove None values from params + params = {k: v for k, v in params.items() if v is not None} + + # Validate request before sending + validator.validate_json(params, "GetDecisionLogs") + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_logs_invalid_auth(api_client, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/decision endpoint with invalid authentication. + """ + ownerID = scenario_case.get("ownerID", "invalid-owner-id") + context = scenario_case.get("context", "invalid-context") + endpoint = f"/owner/{ownerID}/context/{context}/decision" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={"Authorization": "Bearer invalid_token"}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_post.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_post.py new file mode 100644 index 00000000..53951ade --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_post.py @@ -0,0 +1,90 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/decision_post for http method type POST +# RoostTestHash=b8f77c5380 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_decision.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_post_owner_context_decision(api_client, config_test_data, scenario_case): + """ + Test the POST /owner/{ownerID}/context/{context}/decision endpoint. + """ + ownerID = scenario_case.get('ownerID', config_test_data['ownerID']) + context = scenario_case.get('context', config_test_data['context']) + endpoint = f"/owner/{ownerID}/context/{context}/decision" + + # Prepare request data + request_data = {} + if 'input' in scenario_case: + request_data['input'] = scenario_case['input'] + if 'metadata' in scenario_case: + request_data['metadata'] = scenario_case['metadata'] + + # Validate request data + if request_data: + validation_result = validator.validate_json(request_data, 'MakeDecisionRequest') + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'post', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_post_owner_context_decision_invalid_auth(api_client, scenario_case): + """ + Test the POST /owner/{ownerID}/context/{context}/decision endpoint with invalid authentication. + """ + ownerID = scenario_case.get('ownerID', 'invalid_owner') + context = scenario_case.get('context', 'invalid_context') + endpoint = f"/owner/{ownerID}/context/{context}/decision" + + # Prepare request data + request_data = {} + if 'input' in scenario_case: + request_data['input'] = scenario_case['input'] + if 'metadata' in scenario_case: + request_data['metadata'] = scenario_case['metadata'] + + # Make API request with invalid auth + response = api_client.session.post( + f"{api_client.host}/{endpoint.lstrip('/')}", + headers={'Authorization': 'Bearer invalid_token'}, + json=request_data + ) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'post', '401', response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_get.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_get.py new file mode 100644 index 00000000..3512ba96 --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_get.py @@ -0,0 +1,112 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/decision/settings_get for http method type GET +# RoostTestHash=1c47fdb6d9 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_decision_settings.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_settings(api_client, config_test_data, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/decision/settings endpoint. + """ + ownerID = scenario_case.get('ownerID', config_test_data['ownerID']) + context = scenario_case.get('context', config_test_data['context']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_settings_unauthorized(api_client, scenario_case): + """ + Test unauthorized access to /owner/{ownerID}/context/{context}/decision/settings endpoint. + """ + ownerID = scenario_case.get('ownerID', 'invalid-owner-id') + context = scenario_case.get('context', 'invalid-context') + expected_status_code = 401 + + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_settings_forbidden(api_client, scenario_case): + """ + Test forbidden access to /owner/{ownerID}/context/{context}/decision/settings endpoint. + """ + ownerID = scenario_case.get('ownerID', 'forbidden-owner-id') + context = scenario_case.get('context', 'forbidden-context') + expected_status_code = 403 + + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + + # Make the API request with forbidden access + response = api_client.get(endpoint, headers={'Authorization': 'Bearer forbidden_token'}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_decision_settings_server_error(api_client, scenario_case): + """ + Test server error for /owner/{ownerID}/context/{context}/decision/settings endpoint. + """ + ownerID = scenario_case.get('ownerID', 'server-error-owner-id') + context = scenario_case.get('context', 'server-error-context') + expected_status_code = 500 + + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + + # Simulate server error + response = api_client.get(endpoint, headers={'Authorization': 'Bearer server_error_token'}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_patch.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_patch.py new file mode 100644 index 00000000..a354f569 --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_decision_settings_patch.py @@ -0,0 +1,105 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/decision/settings_patch for http method type PATCH +# RoostTestHash=bd818463ad +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +TEST_DATA_FILENAME = 'owner_ownerID_context_context_decision_settings.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_set_decision_settings(api_client, config_test_data, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/decision/settings endpoint. + """ + # Prepare endpoint and request data + ownerID = scenario_case.get('ownerID', config_test_data['ownerID']) + context = scenario_case.get('context', config_test_data['context']) + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + payload = {"enabled": scenario_case['enabled']} + + # Validate request payload + validator.validate_json(payload, 'SetDecisionSettingsRequest') + + # Make API request + response = api_client.patch(endpoint, json=payload) + + # Validate response + assert response.status_code == scenario_case['statusCode'] + validation_result = validator.validate_schema_by_response( + endpoint, 'PATCH', str(response.status_code), response + ) + assert validation_result['valid'], validation_result['message'] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_set_decision_settings_invalid_auth(api_client, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/decision/settings endpoint with invalid auth. + """ + ownerID = scenario_case.get('ownerID', config_test_data['ownerID']) + context = scenario_case.get('context', config_test_data['context']) + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + payload = {"enabled": scenario_case['enabled']} + + # Validate request payload + validator.validate_json(payload, 'SetDecisionSettingsRequest') + + # Make API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.patch(endpoint, json=payload, headers=headers) + + # Validate response + assert response.status_code == 401 + validation_result = validator.validate_schema_by_response( + endpoint, 'PATCH', '401', response + ) + assert validation_result['valid'], validation_result['message'] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_set_decision_settings_missing_auth(api_client, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/decision/settings endpoint with missing auth. + """ + ownerID = scenario_case.get('ownerID', config_test_data['ownerID']) + context = scenario_case.get('context', config_test_data['context']) + endpoint = f"/owner/{ownerID}/context/{context}/decision/settings" + payload = {"enabled": scenario_case['enabled']} + + # Validate request payload + validator.validate_json(payload, 'SetDecisionSettingsRequest') + + # Make API request without auth + response = api_client.patch(endpoint, json=payload, headers={}) + + # Validate response + assert response.status_code == 401 + validation_result = validator.validate_schema_by_response( + endpoint, 'PATCH', '401', response + ) + assert validation_result['valid'], validation_result['message'] diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_get.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_get.py new file mode 100644 index 00000000..84f898a1 --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_get.py @@ -0,0 +1,109 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/policy-bundle_get for http method type GET +# RoostTestHash=3de463fe27 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_policy-bundle.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['ownerID']}-{case['context']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle(api_client, config_test_data, scenario_case): + """ + Test the retrieval of policy bundles with various scenarios. + """ + ownerID = scenario_case.get('ownerID', config_test_data['ownerID']) + context = scenario_case.get('context', config_test_data['context']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/owner/{ownerID}/context/{context}/policy-bundle" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle_unauthorized(api_client, scenario_case): + """ + Test unauthorized access to policy bundles. + """ + ownerID = scenario_case.get('ownerID', 'invalid-ownerID') + context = scenario_case.get('context', 'invalid-context') + + endpoint = f"/owner/{ownerID}/context/{context}/policy-bundle" + + # Make the API request with invalid token + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle_forbidden(api_client, scenario_case): + """ + Test forbidden access to policy bundles. + """ + ownerID = scenario_case.get('ownerID', 'forbidden-ownerID') + context = scenario_case.get('context', 'forbidden-context') + + endpoint = f"/owner/{ownerID}/context/{context}/policy-bundle" + + # Make the API request with valid token but forbidden access + response = api_client.get(endpoint, headers={'Authorization': 'Bearer valid_but_forbidden_token'}) + + # Validate response status code + assert response.status_code == 403, f"Expected 403 Forbidden, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '403', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_bundle_server_error(api_client, scenario_case): + """ + Test server error when retrieving policy bundles. + """ + ownerID = scenario_case.get('ownerID', 'server-error-ownerID') + context = scenario_case.get('context', 'server-error-context') + + endpoint = f"/owner/{ownerID}/context/{context}/policy-bundle" + + # Simulate server error + response = api_client.get(endpoint, headers={'Authorization': 'Bearer valid_token'}) + + # Validate response status code + assert response.status_code == 500, f"Expected 500 Server Error, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '500', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_policyName_get.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_policyName_get.py new file mode 100644 index 00000000..6ba33e49 --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_policyName_get.py @@ -0,0 +1,124 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/policy-bundle/{policyName}_get for http method type GET +# RoostTestHash=5622d6f310 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_policy-bundle_policy.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_document_success(api_client, config_test_data, scenario_case): + """ + Test the successful retrieval of a policy document. + """ + owner_id = config_test_data['ownerID'] + context = config_test_data['context'] + policy_name = config_test_data['policyName'] + + endpoint = f"/owner/{owner_id}/context/{context}/policy-bundle/{policy_name}" + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'] + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], validation_result.get('message', 'Schema validation failed') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_document_unauthorized(api_client, scenario_case): + """ + Test unauthorized access to the policy document. + """ + owner_id = "invalid-owner-id" + context = "invalid-context" + policy_name = "invalid-policy-name" + + endpoint = f"/owner/{owner_id}/context/{context}/policy-bundle/{policy_name}" + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == 401 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], validation_result.get('message', 'Schema validation failed') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_document_not_found(api_client, scenario_case): + """ + Test the retrieval of a non-existent policy document. + """ + owner_id = "non-existent-owner-id" + context = "non-existent-context" + policy_name = "non-existent-policy-name" + + endpoint = f"/owner/{owner_id}/context/{context}/policy-bundle/{policy_name}" + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == 404 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '404', response) + assert validation_result['valid'], validation_result.get('message', 'Schema validation failed') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_document_server_error(api_client, scenario_case): + """ + Test server error when retrieving a policy document. + """ + owner_id = "server-error-owner-id" + context = "server-error-context" + policy_name = "server-error-policy-name" + + endpoint = f"/owner/{owner_id}/context/{context}/policy-bundle/{policy_name}" + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == 500 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '500', response) + assert validation_result['valid'], validation_result.get('message', 'Schema validation failed') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_policy_document_forbidden(api_client, scenario_case): + """ + Test forbidden access to the policy document. + """ + owner_id = "forbidden-owner-id" + context = "forbidden-context" + policy_name = "forbidden-policy-name" + + endpoint = f"/owner/{owner_id}/context/{context}/policy-bundle/{policy_name}" + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == 403 + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '403', response) + assert validation_result['valid'], validation_result.get('message', 'Schema validation failed') diff --git a/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_post.py b/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_post.py new file mode 100644 index 00000000..757bb404 --- /dev/null +++ b/tests/CIRCLECI_API/test_owner_ownerID_context_context_policy-bundle_post.py @@ -0,0 +1,87 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /owner/{ownerID}/context/{context}/policy-bundle_post for http method type POST +# RoostTestHash=d08268b7a2 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'owner_ownerID_context_context_policy-bundle.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_policy_bundle(api_client, config_test_data, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/policy-bundle endpoint. + """ + ownerID = scenario_case.get("ownerID", config_test_data['ownerID']) + context = scenario_case.get("context", config_test_data['context']) + dry = scenario_case.get("dry", False) + policies = scenario_case.get("policies", {}) + + endpoint = f"owner/{ownerID}/context/{context}/policy-bundle" + params = {'dry': dry} + payload = {'policies': policies} + + # Validate request payload + request_validation = validator.validate_json(payload, 'CreatePolicyBundleRequest') + assert request_validation['valid'], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=payload, params=params) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_policy_bundle_invalid_auth(api_client, scenario_case): + """ + Test the /owner/{ownerID}/context/{context}/policy-bundle endpoint with invalid authentication. + """ + ownerID = scenario_case.get("ownerID", "invalid-owner") + context = scenario_case.get("context", "invalid-context") + dry = scenario_case.get("dry", False) + policies = scenario_case.get("policies", {}) + + endpoint = f"owner/{ownerID}/context/{context}/policy-bundle" + params = {'dry': dry} + payload = {'policies': policies} + + # Make API request with invalid auth + response = api_client.session.post( + f"{api_client.host}/{endpoint}", + headers={'Authorization': 'Bearer invalid_token'}, + json=payload, + params=params + ) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', '401', response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_pipeline_continue_post.py b/tests/CIRCLECI_API/test_pipeline_continue_post.py new file mode 100644 index 00000000..18bb08c6 --- /dev/null +++ b/tests/CIRCLECI_API/test_pipeline_continue_post.py @@ -0,0 +1,105 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /pipeline/continue_post for http method type POST +# RoostTestHash=ee13c42d57 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /pipeline/continue endpoint. + +This suite tests the continuation of a pipeline using the CircleCI API. +Ensure that the config.yml file is properly set up with the necessary +host and authentication details before running the tests. + +To run the tests, use the command: +pytest test_pipeline_continue.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'pipeline_continue.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_pipeline_continue(api_client, config_test_data, scenario_case): + """ + Test the /pipeline/continue endpoint with various scenarios. + """ + endpoint = '/pipeline/continue' + method = 'POST' + headers = {'Content-Type': 'application/json'} + + # Merge default test data with scenario-specific data + test_data = config_test_data.copy() + test_data.update(scenario_case) + + # Prepare request payload + payload = { + "continuation-key": test_data.get("continuation-key"), + "configuration": test_data.get("configuration", ""), + "parameters": test_data.get("parameters", {}) + } + + # Validate request payload + validation_result = validator.validate_json(payload, "PipelineContinuationKey") + assert validation_result['valid'], f"Request validation failed: {validation_result['message']}" + + # Make API request + response = api_client.post(endpoint, headers=headers, json=payload) + + # Validate response status code + expected_status_code = test_data['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + schema_validation = validator.validate_schema_by_response(endpoint, method, str(response.status_code), response) + assert schema_validation['valid'], f"Response validation failed: {schema_validation['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_pipeline_continue_invalid_auth(api_client, scenario_case): + """ + Test the /pipeline/continue endpoint with invalid authentication. + """ + endpoint = '/pipeline/continue' + method = 'POST' + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer invalid_token'} + + # Prepare request payload + payload = { + "continuation-key": scenario_case.get("continuation-key"), + "configuration": scenario_case.get("configuration", ""), + "parameters": scenario_case.get("parameters", {}) + } + + # Make API request + response = api_client.post(endpoint, headers=headers, json=payload) + + # Validate response status code for invalid auth + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + schema_validation = validator.validate_schema_by_response(endpoint, method, str(response.status_code), response) + assert schema_validation['valid'], f"Response validation failed: {schema_validation['message']}" diff --git a/tests/CIRCLECI_API/test_pipeline_get.py b/tests/CIRCLECI_API/test_pipeline_get.py new file mode 100644 index 00000000..d10d8cac --- /dev/null +++ b/tests/CIRCLECI_API/test_pipeline_get.py @@ -0,0 +1,84 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /pipeline_get for http method type GET +# RoostTestHash=2a8f9b2e24 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'pipeline.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"Scenario: {case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipelines(api_client, config_test_data, scenario_case): + """ + Test the /pipeline endpoint with various scenarios. + """ + # Prepare request parameters + params = { + "org-slug": scenario_case.get("org-slug", config_test_data.get("org-slug")), + "page-token": scenario_case.get("page-token"), + "mine": scenario_case.get("mine") + } + params = {k: v for k, v in params.items() if v is not None} + + # Validate request parameters + validator.validate_json(params, "PipelineListRequest") + + # Make API request + response = api_client.get("/pipeline", params=params) + + # Validate response status code + expected_status_code = scenario_case["statusCode"] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/pipeline", "GET", str(expected_status_code), response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipelines_invalid_auth(api_client, scenario_case): + """ + Test the /pipeline endpoint with invalid authentication. + """ + # Prepare request parameters + params = { + "org-slug": scenario_case.get("org-slug"), + "page-token": scenario_case.get("page-token"), + "mine": scenario_case.get("mine") + } + params = {k: v for k, v in params.items() if v is not None} + + # Make API request with invalid token + headers = {"Authorization": "Bearer invalid_token"} + response = api_client.get("/pipeline", params=params, headers=headers) + + # Validate response status code for invalid auth + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema for error + validation_result = validator.validate_schema_by_response("/pipeline", "GET", "default", response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_pipeline_pipeline-id_config_get.py b/tests/CIRCLECI_API/test_pipeline_pipeline-id_config_get.py new file mode 100644 index 00000000..0f1839a6 --- /dev/null +++ b/tests/CIRCLECI_API/test_pipeline_pipeline-id_config_get.py @@ -0,0 +1,79 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /pipeline/{pipeline-id}/config_get for http method type GET +# RoostTestHash=44d8f0ed9d +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI API endpoint /pipeline/{pipeline-id}/config. + +This suite uses pytest fixtures and the SwaggerSchemaValidator for validating API responses +against the OpenAPI specification. It covers various scenarios including successful responses, +authentication errors, and other edge cases. + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place this test file in the same directory as the conftest.py and validator.py files. +3. Run the tests using the command: pytest .py +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'pipeline_pipeline-id_config.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"pipeline-id: {case['pipeline-id']}, scenario: {case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_config(api_client, config_test_data, scenario_case): + """ + Test the /pipeline/{pipeline-id}/config endpoint for various scenarios. + """ + pipeline_id = scenario_case['pipeline-id'] + expected_status_code = scenario_case['statusCode'] + + # Construct the endpoint path + endpoint = f"/pipeline/{pipeline_id}/config" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_config_invalid_auth(api_client, scenario_case): + """ + Test the /pipeline/{pipeline-id}/config endpoint with invalid authentication. + """ + pipeline_id = scenario_case['pipeline-id'] + endpoint = f"/pipeline/{pipeline_id}/config" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate the response status code for unauthorized access + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate the response schema for error + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_pipeline_pipeline-id_get.py b/tests/CIRCLECI_API/test_pipeline_pipeline-id_get.py new file mode 100644 index 00000000..45da97a5 --- /dev/null +++ b/tests/CIRCLECI_API/test_pipeline_pipeline-id_get.py @@ -0,0 +1,102 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /pipeline/{pipeline-id}_get for http method type GET +# RoostTestHash=8cd9f60556 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI Pipeline API. + +This test suite covers the following: +- Endpoint: /pipeline/{pipeline-id} +- Method: GET +- Security: API Key in Header +- Response Codes: 200, default (error) + +Instructions for running the tests: +1. Ensure pytest is installed: `pip install pytest` +2. Place this file in the same directory as `conftest.py`, `validator.py`, and `config.yml`. +3. Run the tests using the command: `pytest .py` + +Note: The test data is loaded from `pipeline_pipeline-id.json`. +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'pipeline_pipeline-id.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_by_id(api_client, config_test_data, scenario_case): + """ + Test the GET /pipeline/{pipeline-id} endpoint. + """ + # Override default test data with scenario specific data + test_data = config_test_data.copy() + test_data.update(scenario_case) + + # Extract pipeline-id from test data + pipeline_id = test_data.get("pipeline-id") + if not pipeline_id: + pytest.skip("Missing required pipeline-id in test data") + + # Construct endpoint + endpoint = f"/pipeline/{pipeline_id}" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + expected_status_code = scenario_case.get("statusCode") + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_by_id_invalid_auth(api_client, scenario_case): + """ + Test the GET /pipeline/{pipeline-id} endpoint with invalid authentication. + """ + # Extract pipeline-id from test data + pipeline_id = scenario_case.get("pipeline-id") + if not pipeline_id: + pytest.skip("Missing required pipeline-id in test data") + + # Construct endpoint + endpoint = f"/pipeline/{pipeline_id}" + + # Make API request with invalid auth + invalid_headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=invalid_headers) + + # Validate response status code for invalid auth + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate error response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_pipeline_pipeline-id_values_get.py b/tests/CIRCLECI_API/test_pipeline_pipeline-id_values_get.py new file mode 100644 index 00000000..98909e28 --- /dev/null +++ b/tests/CIRCLECI_API/test_pipeline_pipeline-id_values_get.py @@ -0,0 +1,101 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /pipeline/{pipeline-id}/values_get for http method type GET +# RoostTestHash=2981b2028e +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI API endpoint /pipeline/{pipeline-id}/values. + +Setup: +- Ensure the config.yml file is correctly configured with the API host and authentication details. +- Place the pipeline_pipeline-id_values.json file in the same directory as this test file. + +Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import APIClient + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'pipeline_pipeline-id_values.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"pipeline-id: {case['pipeline-id']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_values_by_id(api_client: APIClient, config_test_data, scenario_case): + """ + Test the /pipeline/{pipeline-id}/values endpoint with various scenarios. + """ + pipeline_id = scenario_case['pipeline-id'] + expected_status_code = scenario_case['statusCode'] + endpoint = f"/pipeline/{pipeline_id}/values" + + # Validate request schema before sending + request_data = {"pipeline-id": pipeline_id} + validation_result = validator.validate_json(request_data, "PipelineValues") + assert validation_result['valid'], f"Request validation failed: {validation_result['message']}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_values_by_id_invalid_auth(api_client: APIClient, scenario_case): + """ + Test the /pipeline/{pipeline-id}/values endpoint with invalid authentication. + """ + pipeline_id = scenario_case['pipeline-id'] + endpoint = f"/pipeline/{pipeline_id}/values" + + # Make the API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_values_by_id_missing_auth(api_client: APIClient, scenario_case): + """ + Test the /pipeline/{pipeline-id}/values endpoint with missing authentication. + """ + pipeline_id = scenario_case['pipeline-id'] + endpoint = f"/pipeline/{pipeline_id}/values" + + # Make the API request without token + headers = {} + response = api_client.get(endpoint, headers=headers) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" diff --git a/tests/CIRCLECI_API/test_pipeline_pipeline-id_workflow_get.py b/tests/CIRCLECI_API/test_pipeline_pipeline-id_workflow_get.py new file mode 100644 index 00000000..555fc39c --- /dev/null +++ b/tests/CIRCLECI_API/test_pipeline_pipeline-id_workflow_get.py @@ -0,0 +1,61 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /pipeline/{pipeline-id}/workflow_get for http method type GET +# RoostTestHash=840fe668da +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'pipeline_pipeline-id_workflow.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_workflows(api_client, config_test_data, scenario_case): + """ + Test the GET /pipeline/{pipeline-id}/workflow endpoint with various scenarios. + """ + # Setup + pipeline_id = scenario_case.get('pipeline-id', config_test_data['pipeline-id']) + page_token = scenario_case.get('page-token', None) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint + endpoint = f"/pipeline/{pipeline_id}/workflow" + params = {} + if page_token: + params['page-token'] = page_token + + # Execute + try: + response = api_client.get(endpoint, params=params) + except requests.exceptions.HTTPError as e: + response = e.response + + # Validate response + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + if response.status_code == 200: + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '200', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" + else: + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_delete.py b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_delete.py new file mode 100644 index 00000000..7a689445 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_delete.py @@ -0,0 +1,100 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/checkout-key/{fingerprint}_delete for http method type DELETE +# RoostTestHash=a3f9746899 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_checkout-key_fingerprint.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_checkout_key(api_client, config_test_data, scenario_case): + """ + Test the DELETE /project/{project-slug}/checkout-key/{fingerprint} endpoint. + """ + # Setup + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + fingerprint = scenario_case.get('fingerprint', config_test_data['fingerprint']) + endpoint = f"/project/{project_slug}/checkout-key/{fingerprint}" + + # Validate request schema + request_data = {} + validator.validate_json(request_data, 'MessageResponse') + + # Make API request + try: + response = api_client.delete(endpoint) + except requests.exceptions.HTTPError as e: + response = e.response + + # Validate response schema + status_code = scenario_case['statusCode'] + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', status_code, response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Assertions + assert response.status_code == status_code, f"Expected status code {status_code}, got {response.status_code}" + if status_code == 200: + response_data = response.json() + assert 'message' in response_data, "Response JSON does not contain 'message'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_checkout_key_invalid_auth(api_client, scenario_case): + """ + Test the DELETE /project/{project-slug}/checkout-key/{fingerprint} endpoint with invalid auth. + """ + # Setup + project_slug = scenario_case.get('project-slug', 'invalid-project') + fingerprint = scenario_case.get('fingerprint', 'invalid-fingerprint') + endpoint = f"/project/{project_slug}/checkout-key/{fingerprint}" + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.delete(f"{api_client.host}/{endpoint}", headers=headers) + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Assertions + assert response.status_code != 200, "Expected non-200 status code for invalid auth" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_checkout_key_missing_auth(api_client, scenario_case): + """ + Test the DELETE /project/{project-slug}/checkout-key/{fingerprint} endpoint with missing auth. + """ + # Setup + project_slug = scenario_case.get('project-slug', 'missing-auth-project') + fingerprint = scenario_case.get('fingerprint', 'missing-auth-fingerprint') + endpoint = f"/project/{project_slug}/checkout-key/{fingerprint}" + + # Make API request without token + response = api_client.session.delete(f"{api_client.host}/{endpoint}") + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Assertions + assert response.status_code != 200, "Expected non-200 status code for missing auth" diff --git a/tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_get.py b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_get.py new file mode 100644 index 00000000..09163308 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_fingerprint_get.py @@ -0,0 +1,72 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/checkout-key/{fingerprint}_get for http method type GET +# RoostTestHash=5885ecc23a +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /project/{project-slug}/checkout-key/{fingerprint} + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `project_project-slug_checkout-key_fingerprint.json` in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. + +Run the tests using pytest: +$ pytest test_api.py +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'project_project-slug_checkout-key_fingerprint.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_checkout_key(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/checkout-key/{fingerprint} endpoint. + """ + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + fingerprint = scenario_case.get('fingerprint', config_test_data['fingerprint']) + endpoint = f"/project/{project_slug}/checkout-key/{fingerprint}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response + if scenario_case['statusCode'] == 200: + assert response.status_code == 200 + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', '200', response + ) + assert validation_result['valid'], validation_result['message'] + elif scenario_case['statusCode'] == 'default': + assert response.status_code not in range(200, 300) + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', 'default', response + ) + assert validation_result['valid'], validation_result['message'] + else: + pytest.skip(f"Unhandled scenario: {scenario_case['scenario']}") diff --git a/tests/CIRCLECI_API/test_project_project-slug_checkout-key_get.py b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_get.py new file mode 100644 index 00000000..1fbee5d1 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_get.py @@ -0,0 +1,67 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/checkout-key_get for http method type GET +# RoostTestHash=5045e5f644 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_checkout-key.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_checkout_keys(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/checkout-key endpoint for various scenarios. + """ + # Setup + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + digest = scenario_case.get('digest', None) + endpoint = f"project/{project_slug}/checkout-key" + params = {} + if digest: + params['digest'] = digest + + # Execute + try: + response = api_client.get(endpoint, params=params) + except Exception as e: + if scenario_case['statusCode'] == 'default': + assert str(e).startswith('4') or str(e).startswith('5'), f"Unexpected error: {e}" + pytest.skip(f"Skipping due to expected error: {e}") + else: + raise + + # Validate + if scenario_case['statusCode'] == 200: + assert response.status_code == 200 + validation_result = validator.validate_schema_by_response( + f"/project/{{project-slug}}/checkout-key", 'get', '200', response + ) + assert validation_result['valid'], f"Validation failed: {validation_result['message']}" + elif scenario_case['statusCode'] == 'default': + validation_result = validator.validate_schema_by_response( + f"/project/{{project-slug}}/checkout-key", 'get', 'default', response + ) + assert not validation_result['valid'], "Expected error response, got valid response" + else: + pytest.fail(f"Unhandled status code: {scenario_case['statusCode']}") diff --git a/tests/CIRCLECI_API/test_project_project-slug_checkout-key_post.py b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_post.py new file mode 100644 index 00000000..4dd278ed --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_checkout-key_post.py @@ -0,0 +1,102 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/checkout-key_post for http method type POST +# RoostTestHash=6516866958 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI API endpoint for creating checkout keys. + +Instructions for running the tests: +- Ensure pytest is installed in your environment. +- Place this test file in the same directory as the `conftest.py` and `validator.py`. +- Ensure the `config.yml` is correctly set up with the necessary API host and authentication details. +- Run the tests using the command: `pytest .py` + +This suite covers: +- Endpoint: /project/{project-slug}/checkout-key +- Method: POST +- Security: API Key in Header +- Response Codes: 201, default (error) +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Constants +TEST_DATA_FILENAME = 'project_project-slug_checkout-key.json' +API_SPEC_PATH = 'api.json' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['project-slug']}" for case in _ENDPOINT_DATA] + +# Initialize the SwaggerSchemaValidator +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_checkout_key(api_client, config_test_data, scenario_case): + """ + Test the creation of a checkout key for a project. + """ + # Prepare endpoint and headers + endpoint = f"/project/{scenario_case['project-slug']}/checkout-key" + headers = {'Content-Type': 'application/json'} + + # Prepare request body + request_body = { + "type": scenario_case["type"] + } + + # Validate request body + validation_result = validator.validate_json(request_body, "CheckoutKeyInput") + assert validation_result["valid"], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_body, headers=headers) + + # Validate response + expected_status_code = scenario_case["statusCode"] + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', str(expected_status_code), response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_checkout_key_invalid_auth(api_client, scenario_case): + """ + Test the creation of a checkout key with invalid authentication. + """ + # Prepare endpoint and headers + endpoint = f"/project/{scenario_case['project-slug']}/checkout-key" + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer invalid_token'} + + # Prepare request body + request_body = { + "type": scenario_case["type"] + } + + # Validate request body + validation_result = validator.validate_json(request_body, "CheckoutKeyInput") + assert validation_result["valid"], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_body, headers=headers) + + # Validate response + assert response.status_code != 201, "Expected failure with invalid auth, but got success" + validation_result = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert validation_result["valid"], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_delete.py b/tests/CIRCLECI_API/test_project_project-slug_delete.py new file mode 100644 index 00000000..25f6a89b --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_delete.py @@ -0,0 +1,96 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}_delete for http method type DELETE +# RoostTestHash=caa6efeb67 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_project_by_slug(api_client, config_test_data, scenario_case): + """ + Test the DELETE /project/{project-slug} endpoint. + """ + # Setup + project_slug = scenario_case.get("project-slug", config_test_data['project-slug']) + expected_status_code = scenario_case["statusCode"] + endpoint = f"project/{project_slug}" + + # Execute + try: + response = api_client.delete(endpoint) + except requests.exceptions.HTTPError as e: + response = e.response + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks for successful response + if response.status_code == 200: + response_data = response.json() + assert "message" in response_data, "Response body missing 'message' field" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_project_by_slug_invalid_auth(api_client, scenario_case): + """ + Test the DELETE /project/{project-slug} endpoint with invalid authentication. + """ + # Setup + project_slug = scenario_case.get("project-slug") + endpoint = f"project/{project_slug}" + headers = {'Authorization': 'Bearer invalid_token'} + + # Execute + response = api_client.make_request(endpoint, method='DELETE', headers=headers) + + # Validate response status code + assert response.status_code != 200, "Expected failure with invalid authentication" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_project_by_slug_missing_auth(api_client, scenario_case): + """ + Test the DELETE /project/{project-slug} endpoint with missing authentication. + """ + # Setup + project_slug = scenario_case.get("project-slug") + endpoint = f"project/{project_slug}" + headers = {} # No auth header + + # Execute + response = api_client.make_request(endpoint, method='DELETE', headers=headers) + + # Validate response status code + assert response.status_code != 200, "Expected failure with missing authentication" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_envvar_get.py b/tests/CIRCLECI_API/test_project_project-slug_envvar_get.py new file mode 100644 index 00000000..299916e2 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_envvar_get.py @@ -0,0 +1,95 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/envvar_get for http method type GET +# RoostTestHash=d8980625aa +# +# + +# ********RoostGPT******** +""" +Pytest test suite for CircleCI API - Environment Variables Endpoint + +This test suite covers the `/project/{project-slug}/envvar` endpoint of the CircleCI API. +It includes tests for successful responses, authentication scenarios, and error handling. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. +- Place `project_project-slug_envvar.json` in the same directory for test data. + +Run the tests using `pytest`. + +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator +import json + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_envvar.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +# Initialize SwaggerSchemaValidator +api_spec_path = _here / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_env_vars(api_client, config_test_data, scenario_case): + """ + Test the `/project/{project-slug}/envvar` endpoint for various scenarios. + """ + # Prepare endpoint and headers + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + endpoint = f"project/{project_slug}/envvar" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/project/{{project-slug}}/envvar", + method='GET', + status_code=str(expected_status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_env_vars_invalid_auth(api_client, scenario_case): + """ + Test the `/project/{project-slug}/envvar` endpoint with invalid authentication. + """ + # Prepare endpoint and headers + project_slug = scenario_case.get('project-slug', 'invalid-project') + endpoint = f"project/{project_slug}/envvar" + + # Override headers with invalid token + invalid_headers = {'Authorization': 'Bearer invalid_token'} + + # Make API request + response = api_client.get(endpoint, headers=invalid_headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/project/{{project-slug}}/envvar", + method='GET', + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_envvar_name_delete.py b/tests/CIRCLECI_API/test_project_project-slug_envvar_name_delete.py new file mode 100644 index 00000000..96ddc347 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_envvar_name_delete.py @@ -0,0 +1,70 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/envvar/{name}_delete for http method type DELETE +# RoostTestHash=a050713778 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_envvar_name.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_env_var(api_client, config_test_data, scenario_case): + """ + Test the DELETE /project/{project-slug}/envvar/{name} endpoint. + """ + # Prepare endpoint and headers + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + name = scenario_case.get('name', config_test_data['name']) + endpoint = f"/project/{project_slug}/envvar/{name}" + + # Make DELETE request + response = api_client.delete(endpoint) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_env_var_invalid_auth(api_client, scenario_case): + """ + Test the DELETE /project/{project-slug}/envvar/{name} endpoint with invalid authentication. + """ + # Prepare endpoint and headers + project_slug = scenario_case.get('project-slug', 'invalid-project') + name = scenario_case.get('name', 'invalid-name') + endpoint = f"/project/{project_slug}/envvar/{name}" + + # Make DELETE request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.request('DELETE', f"{api_client.host}/{endpoint.lstrip('/')}", headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_envvar_name_get.py b/tests/CIRCLECI_API/test_project_project-slug_envvar_name_get.py new file mode 100644 index 00000000..d9546528 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_envvar_name_get.py @@ -0,0 +1,81 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/envvar/{name}_get for http method type GET +# RoostTestHash=7146dab6cd +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI API endpoint: /project/{project-slug}/envvar/{name} + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `config.yml` in the same directory with necessary configurations. +- Ensure `project_project-slug_envvar_name.json` is in the same directory for test data. + +Run the tests using pytest: +$ pytest test_api.py +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_envvar_name.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['project-slug']}-{case['name']}-{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_env_var(api_client, config_test_data, scenario_case): + """ + Test the GET /project/{project-slug}/envvar/{name} endpoint. + """ + # Prepare endpoint and parameters + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + name = scenario_case.get('name', config_test_data['name']) + endpoint = f"/project/{project_slug}/envvar/{name}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_env_var_invalid_auth(api_client, scenario_case): + """ + Test the GET /project/{project-slug}/envvar/{name} endpoint with invalid authentication. + """ + # Prepare endpoint and parameters + project_slug = scenario_case.get('project-slug', 'invalid-project') + name = scenario_case.get('name', 'invalid-name') + endpoint = f"/project/{project_slug}/envvar/{name}" + + # Make the API request with invalid token + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_envvar_post.py b/tests/CIRCLECI_API/test_project_project-slug_envvar_post.py new file mode 100644 index 00000000..5dc14d81 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_envvar_post.py @@ -0,0 +1,103 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/envvar_post for http method type POST +# RoostTestHash=d22cc7269f +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_envvar.json' +with open(_endpoint_data_path) as f: + _ENDPOINT_DATA = json.load(f) + +# Parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_env_var(api_client, config_test_data, scenario_case): + """ + Test creating an environment variable with various scenarios. + """ + # Setup + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + endpoint = f"/project/{project_slug}/envvar" + payload = { + "name": scenario_case.get('name', config_test_data['name']), + "value": scenario_case.get('value', config_test_data['value']) + } + + # Validate request payload + request_validation = validator.validate_json(payload, "EnvironmentVariable") + assert request_validation['valid'], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=payload) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_env_var_invalid_auth(api_client, scenario_case): + """ + Test creating an environment variable with invalid authentication. + """ + # Setup + project_slug = scenario_case.get('project-slug', 'invalid-slug') + endpoint = f"/project/{project_slug}/envvar" + payload = { + "name": scenario_case.get('name', 'invalid-name'), + "value": scenario_case.get('value', 'invalid-value') + } + + # Make API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.post(f"{api_client.host}/{endpoint.lstrip('/')}", json=payload, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_env_var_missing_auth(api_client, scenario_case): + """ + Test creating an environment variable with missing authentication. + """ + # Setup + project_slug = scenario_case.get('project-slug', 'missing-auth-slug') + endpoint = f"/project/{project_slug}/envvar" + payload = { + "name": scenario_case.get('name', 'missing-auth-name'), + "value": scenario_case.get('value', 'missing-auth-value') + } + + # Make API request without auth + response = api_client.session.post(f"{api_client.host}/{endpoint.lstrip('/')}", json=payload) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_get.py b/tests/CIRCLECI_API/test_project_project-slug_get.py new file mode 100644 index 00000000..830e805d --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_get.py @@ -0,0 +1,89 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}_get for http method type GET +# RoostTestHash=8d97025ec4 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_by_slug(api_client, config_test_data, scenario_case): + """ + Test the GET /project/{project-slug} endpoint. + """ + # Prepare endpoint and headers + project_slug = scenario_case.get("project-slug", config_test_data['project-slug']) + endpoint = f"project/{project_slug}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + expected_status_code = scenario_case.get("statusCode", 200) + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/project/{{project-slug}}", + method="GET", + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional assertions based on scenario + if response.status_code == 200: + data = response.json() + assert 'slug' in data, "Response JSON does not contain 'slug'" + assert 'name' in data, "Response JSON does not contain 'name'" + assert 'id' in data, "Response JSON does not contain 'id'" + assert 'organization_name' in data, "Response JSON does not contain 'organization_name'" + assert 'organization_slug' in data, "Response JSON does not contain 'organization_slug'" + assert 'organization_id' in data, "Response JSON does not contain 'organization_id'" + assert 'vcs_info' in data, "Response JSON does not contain 'vcs_info'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_by_slug_invalid_auth(api_client, scenario_case): + """ + Test the GET /project/{project-slug} endpoint with invalid authentication. + """ + # Prepare endpoint and headers + project_slug = scenario_case.get("project-slug", "invalid/slug") + endpoint = f"project/{project_slug}" + + # Make the API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers) + + # Validate response status code for unauthorized access + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/project/{{project-slug}}", + method="GET", + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_job-number_artifacts_get.py b/tests/CIRCLECI_API/test_project_project-slug_job-number_artifacts_get.py new file mode 100644 index 00000000..cc3550d4 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_job-number_artifacts_get.py @@ -0,0 +1,70 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/{job-number}/artifacts_get for http method type GET +# RoostTestHash=64af01a4d5 +# +# + +# ********RoostGPT******** +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_job-number_artifacts.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['project-slug']}-{case['job-number']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_artifacts(api_client, config_test_data, scenario_case): + """ + Test the GET /project/{project-slug}/{job-number}/artifacts endpoint. + """ + # Override config_test_data with scenario specific data + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + job_number = scenario_case.get('job-number', config_test_data['job-number']) + + endpoint = f"project/{project_slug}/{job_number}/artifacts" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation error: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_artifacts_invalid_auth(api_client, scenario_case): + """ + Test the GET /project/{project-slug}/{job-number}/artifacts endpoint with invalid authentication. + """ + project_slug = scenario_case.get('project-slug', 'invalid-slug') + job_number = scenario_case.get('job-number', 'invalid-number') + + endpoint = f"project/{project_slug}/{job_number}/artifacts" + + # Simulate invalid authentication by removing the auth header + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation error: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_job-number_tests_get.py b/tests/CIRCLECI_API/test_project_project-slug_job-number_tests_get.py new file mode 100644 index 00000000..e486f71a --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_job-number_tests_get.py @@ -0,0 +1,86 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/{job-number}/tests_get for http method type GET +# RoostTestHash=45b303385b +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI API endpoint: /project/{project-slug}/{job-number}/tests + +Setup: +- Ensure the config.yml file is correctly set up with the necessary API host and authentication details. +- Place the project_project-slug_job-number_tests.json file in the same directory as this test file. + +Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification for validation +API_SPEC_PATH = Path(__file__).parent / "api.json" +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = "project_project-slug_job-number_tests.json" +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['project-slug']}-{case['job-number']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_tests_endpoint(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/{job-number}/tests endpoint for various scenarios. + """ + # Override default test data with scenario-specific data + project_slug = scenario_case.get("project-slug", config_test_data["project-slug"]) + job_number = scenario_case.get("job-number", config_test_data["job-number"]) + + # Construct the endpoint path + endpoint = f"project/{project_slug}/{job_number}/tests" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + expected_status_code = scenario_case["statusCode"] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_tests_endpoint_invalid_auth(api_client, scenario_case): + """ + Test the /project/{project-slug}/{job-number}/tests endpoint with invalid authentication. + """ + # Override default test data with scenario-specific data + project_slug = scenario_case.get("project-slug", "invalid-slug") + job_number = scenario_case.get("job-number", "invalid-job") + + # Construct the endpoint path + endpoint = f"project/{project_slug}/{job_number}/tests" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={"Authorization": "Bearer invalid_token"}) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_job_job-number_cancel_post.py b/tests/CIRCLECI_API/test_project_project-slug_job_job-number_cancel_post.py new file mode 100644 index 00000000..4035bcc5 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_job_job-number_cancel_post.py @@ -0,0 +1,109 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/job/{job-number}/cancel_post for http method type POST +# RoostTestHash=0610594a8e +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_job_job-number_cancel.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_job_by_job_number(api_client, config_test_data, scenario_case): + """ + Test the cancel job by job number endpoint. + """ + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + job_number = scenario_case.get('job-number', config_test_data['job-number']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/project/{project_slug}/job/{job_number}/cancel" + + # Perform the API request + response = api_client.post(endpoint) + + # Validate the response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_job_by_job_number_invalid_auth(api_client, scenario_case): + """ + Test the cancel job by job number endpoint with invalid authentication. + """ + project_slug = scenario_case.get('project-slug') + job_number = scenario_case.get('job-number') + + endpoint = f"/project/{project_slug}/job/{job_number}/cancel" + + # Perform the API request with invalid auth + response = api_client.post(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_job_by_job_number_missing_auth(api_client, scenario_case): + """ + Test the cancel job by job number endpoint with missing authentication. + """ + project_slug = scenario_case.get('project-slug') + job_number = scenario_case.get('job-number') + + endpoint = f"/project/{project_slug}/job/{job_number}/cancel" + + # Perform the API request without auth + response = api_client.post(endpoint, headers={}) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_job_by_job_number_expired_token(api_client, scenario_case): + """ + Test the cancel job by job number endpoint with expired token. + """ + project_slug = scenario_case.get('project-slug') + job_number = scenario_case.get('job-number') + + endpoint = f"/project/{project_slug}/job/{job_number}/cancel" + + # Perform the API request with expired token + response = api_client.post(endpoint, headers={'Authorization': 'Bearer expired_token'}) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_job_job-number_get.py b/tests/CIRCLECI_API/test_project_project-slug_job_job-number_get.py new file mode 100644 index 00000000..d61cbc2d --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_job_job-number_get.py @@ -0,0 +1,147 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/job/{job-number}_get for http method type GET +# RoostTestHash=a4bc177ec8 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_job_job-number.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['job-number']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_details_success(api_client, config_test_data, scenario_case): + """ + Test the successful retrieval of job details. + """ + # Override default test data with scenario-specific data + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + job_number = scenario_case.get('job-number', config_test_data['job-number']) + + # Construct the endpoint + endpoint = f"/project/{project_slug}/job/{job_number}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == scenario_case['statusCode'] + + # Validate the response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', str(response.status_code), response + ) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_details_invalid_auth(api_client, scenario_case): + """ + Test retrieval of job details with invalid authentication. + """ + project_slug = scenario_case.get('project-slug', 'invalid-slug') + job_number = scenario_case.get('job-number', 'invalid-number') + + endpoint = f"/project/{project_slug}/job/{job_number}" + + # Make the API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate the response status code + assert response.status_code == 401 + + # Validate the response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', 'default', response + ) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_details_missing_auth(api_client, scenario_case): + """ + Test retrieval of job details without authentication. + """ + project_slug = scenario_case.get('project-slug', 'missing-auth-slug') + job_number = scenario_case.get('job-number', 'missing-auth-number') + + endpoint = f"/project/{project_slug}/job/{job_number}" + + # Make the API request without auth + response = api_client.get(endpoint, headers={}) + + # Validate the response status code + assert response.status_code == 401 + + # Validate the response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', 'default', response + ) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_details_not_found(api_client, scenario_case): + """ + Test retrieval of job details for a non-existent job. + """ + project_slug = scenario_case.get('project-slug', 'non-existent-slug') + job_number = scenario_case.get('job-number', 'non-existent-number') + + endpoint = f"/project/{project_slug}/job/{job_number}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == 404 + + # Validate the response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', 'default', response + ) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_job_details_server_error(api_client, scenario_case): + """ + Test retrieval of job details when server error occurs. + """ + project_slug = scenario_case.get('project-slug', 'server-error-slug') + job_number = scenario_case.get('job-number', 'server-error-number') + + endpoint = f"/project/{project_slug}/job/{job_number}" + + # Simulate server error + response = api_client.get(endpoint) + + # Validate the response status code + assert response.status_code == 500 + + # Validate the response schema + validation_result = validator.validate_schema_by_response( + endpoint, 'GET', 'default', response + ) + assert validation_result['valid'], validation_result.get('message', '') + +""" +Instructions for running the tests: +1. Ensure the API server is running and accessible. +2. Set the environment variables for API_HOST and Circle-Token. +3. Run the tests using pytest: `pytest test_api.py` +""" diff --git a/tests/CIRCLECI_API/test_project_project-slug_pipeline_get.py b/tests/CIRCLECI_API/test_project_project-slug_pipeline_get.py new file mode 100644 index 00000000..bd56a196 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_pipeline_get.py @@ -0,0 +1,96 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/pipeline_get for http method type GET +# RoostTestHash=f1a5056c61 +# +# + +# ********RoostGPT******** +""" +Test suite for the CircleCI API endpoint: /project/{project-slug}/pipeline + +This test suite uses pytest and the SwaggerSchemaValidator to validate the API's +responses against the OpenAPI specification. It covers various scenarios including +authentication, response validation, and error handling. + +To run the tests, ensure you have pytest installed and execute: +pytest .py +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load endpoint test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_pipeline.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipelines_for_project(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/pipeline endpoint for various scenarios. + """ + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint path + endpoint = f"project/{test_data['project-slug']}/pipeline" + + # Prepare query parameters + params = {} + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate the response status code + assert response.status_code == test_data['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(test_data['statusCode']), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipelines_for_project_invalid_auth(api_client, scenario_case): + """ + Test the /project/{project-slug}/pipeline endpoint with invalid authentication. + """ + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint path + endpoint = f"project/{test_data['project-slug']}/pipeline" + + # Prepare query parameters + params = {} + if 'branch' in test_data: + params['branch'] = test_data['branch'] + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + + # Make the API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, params=params, headers=headers) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_pipeline_mine_get.py b/tests/CIRCLECI_API/test_project_project-slug_pipeline_mine_get.py new file mode 100644 index 00000000..41edc812 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_pipeline_mine_get.py @@ -0,0 +1,88 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/pipeline/mine_get for http method type GET +# RoostTestHash=2bcea12cee +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_pipeline_mine.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_TEST_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipelines(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/pipeline/mine endpoint. + """ + # Prepare endpoint and parameters + project_slug = scenario_case.get("project-slug", config_test_data['project-slug']) + page_token = scenario_case.get("page-token", "") + endpoint = f"project/{project_slug}/pipeline/mine" + params = {} + if page_token: + params['page-token'] = page_token + + # Validate request schema + request_data = {"project-slug": project_slug, "page-token": page_token} + request_validation = validator.validate_json(request_data, "PipelineListRequest") + assert request_validation["valid"], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.get(endpoint, params=params) + + # Validate response status code + expected_status_code = scenario_case["statusCode"] + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation.get('message')}" + + # Additional assertions based on scenario + if response.status_code == 200: + response_data = response.json() + assert "items" in response_data, "Response missing 'items'" + assert isinstance(response_data["items"], list), "'items' should be a list" + assert "next_page_token" in response_data, "Response missing 'next_page_token'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipelines_invalid_auth(api_client, scenario_case): + """ + Test the /project/{project-slug}/pipeline/mine endpoint with invalid auth. + """ + # Prepare endpoint and parameters + project_slug = scenario_case.get("project-slug", "invalid/slug") + page_token = scenario_case.get("page-token", "") + endpoint = f"project/{project_slug}/pipeline/mine" + params = {} + if page_token: + params['page-token'] = page_token + + # Make API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, params=params, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_pipeline_pipeline-number_get.py b/tests/CIRCLECI_API/test_project_project-slug_pipeline_pipeline-number_get.py new file mode 100644 index 00000000..e14ad20d --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_pipeline_pipeline-number_get.py @@ -0,0 +1,80 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/pipeline/{pipeline-number}_get for http method type GET +# RoostTestHash=de6b302d3c +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_pipeline_pipeline-number.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"case_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_by_number(api_client, config_test_data, scenario_case): + """ + Test the GET /project/{project-slug}/pipeline/{pipeline-number} endpoint. + """ + # Extract test data + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + pipeline_number = scenario_case.get('pipeline-number', config_test_data['pipeline-number']) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint + endpoint = f"/project/{project_slug}/pipeline/{pipeline_number}" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks for successful response + if expected_status_code == 200: + response_data = response.json() + assert 'id' in response_data, "Missing 'id' in response" + assert 'project_slug' in response_data, "Missing 'project_slug' in response" + assert 'number' in response_data, "Missing 'number' in response" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_by_number_invalid_auth(api_client, scenario_case): + """ + Test the GET /project/{project-slug}/pipeline/{pipeline-number} endpoint with invalid authentication. + """ + # Extract test data + project_slug = scenario_case.get('project-slug', 'invalid-slug') + pipeline_number = scenario_case.get('pipeline-number', 'invalid-number') + + # Construct endpoint + endpoint = f"/project/{project_slug}/pipeline/{pipeline_number}" + + # Make API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_pipeline_post.py b/tests/CIRCLECI_API/test_project_project-slug_pipeline_post.py new file mode 100644 index 00000000..4343ea41 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_pipeline_post.py @@ -0,0 +1,79 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/pipeline_post for http method type POST +# RoostTestHash=49d6fffef5 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_pipeline.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_trigger_pipeline(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/pipeline endpoint for triggering a new pipeline. + """ + # Prepare endpoint and request data + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + endpoint = f"/project/{project_slug}/pipeline" + request_data = { + "branch": scenario_case.get('branch'), + "tag": scenario_case.get('tag'), + "parameters": scenario_case.get('parameters', {}) + } + + # Validate request data + validation_result = validator.validate_json(request_data, "TriggerPipelineParameters") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(expected_status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_trigger_pipeline_invalid_auth(api_client, scenario_case): + """ + Test the /project/{project-slug}/pipeline endpoint with invalid authentication. + """ + project_slug = scenario_case.get('project-slug', 'invalid-slug') + endpoint = f"/project/{project_slug}/pipeline" + request_data = { + "branch": scenario_case.get('branch'), + "tag": scenario_case.get('tag'), + "parameters": scenario_case.get('parameters', {}) + } + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.post(f"{api_client.host}/{endpoint.lstrip('/')}", json=request_data, headers=headers) + + # Validate response + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + response_validation = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_schedule_get.py b/tests/CIRCLECI_API/test_project_project-slug_schedule_get.py new file mode 100644 index 00000000..05ceefd7 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_schedule_get.py @@ -0,0 +1,93 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/schedule_get for http method type GET +# RoostTestHash=1376419304 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_schedule.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_schedules(api_client, config_test_data, scenario_case): + """ + Test the /project/{project-slug}/schedule endpoint for various scenarios. + """ + # Override default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint path + project_slug = test_data.get('project-slug') + endpoint = f"project/{project_slug}/schedule" + + # Prepare query parameters + params = {} + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + + # Make the API request + response = api_client.get(endpoint, params=params) + + # Validate the response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional assertions based on the scenario + if expected_status_code == 200: + response_data = response.json() + assert 'items' in response_data, "Response missing 'items' key" + assert isinstance(response_data['items'], list), "'items' should be a list" + if 'next_page_token' in response_data: + assert isinstance(response_data['next_page_token'], (str, type(None))), "'next_page_token' should be a string or None" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_schedules_invalid_auth(api_client, scenario_case): + """ + Test the /project/{project-slug}/schedule endpoint with invalid authentication. + """ + # Override default test data with scenario-specific data + test_data = scenario_case + + # Construct the endpoint path + project_slug = test_data.get('project-slug') + endpoint = f"project/{project_slug}/schedule" + + # Prepare query parameters + params = {} + if 'page-token' in test_data: + params['page-token'] = test_data['page-token'] + + # Make the API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers, params=params) + + # Validate the response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_project_project-slug_schedule_post.py b/tests/CIRCLECI_API/test_project_project-slug_schedule_post.py new file mode 100644 index 00000000..ea39f350 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_project-slug_schedule_post.py @@ -0,0 +1,100 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{project-slug}/schedule_post for http method type POST +# RoostTestHash=902d8798f4 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the RESTful API endpoint /project/{project-slug}/schedule. + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place this test file in the same directory as the `conftest.py` and `validator.py`. +3. Ensure the `config.yml` is correctly configured with your API host and authentication details. +4. Run the tests using the command: `pytest .py` + +This test suite covers: +- Endpoint: /project/{project-slug}/schedule +- Method: POST +- Security: API Key in Header +- Response Codes: 201 (Created), Default (Error) +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_project-slug_schedule.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_schedule(api_client, config_test_data, scenario_case): + """ + Test the creation of a schedule with various scenarios. + """ + # Prepare test data + project_slug = scenario_case.get('project-slug', config_test_data['project-slug']) + endpoint = f"/project/{project_slug}/schedule" + headers = {'Content-Type': 'application/json'} + request_body = { + "name": scenario_case.get('name', config_test_data['name']), + "timetable": scenario_case.get('timetable'), + "attribution-actor": scenario_case.get('attribution-actor', 'current'), + "parameters": scenario_case.get('parameters', config_test_data['parameters']), + "description": scenario_case.get('description', None) + } + + # Validate request schema + validation_result = validator.validate_json(request_body, 'CreateScheduleParameters') + assert validation_result['valid'], f"Request validation failed: {validation_result['message']}" + + # Make API request + response = api_client.post(endpoint, json=request_body, headers=headers) + + # Validate response + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(expected_status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_schedule_invalid_auth(api_client, scenario_case): + """ + Test the creation of a schedule with invalid authentication. + """ + # Prepare test data + project_slug = scenario_case.get('project-slug', 'invalid-slug') + endpoint = f"/project/{project_slug}/schedule" + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer invalid_token'} + request_body = { + "name": scenario_case.get('name', 'Invalid Test'), + "timetable": scenario_case.get('timetable'), + "attribution-actor": scenario_case.get('attribution-actor', 'current'), + "parameters": scenario_case.get('parameters', {}), + "description": scenario_case.get('description', None) + } + + # Make API request + response = api_client.post(endpoint, json=request_body, headers=headers) + + # Validate response + assert response.status_code != 201, "Expected failure with invalid auth" + response_validation = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" diff --git a/tests/CIRCLECI_API/test_project_provider_organization_project_pipeline_run_post.py b/tests/CIRCLECI_API/test_project_provider_organization_project_pipeline_run_post.py new file mode 100644 index 00000000..ea24adc9 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_provider_organization_project_pipeline_run_post.py @@ -0,0 +1,119 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{provider}/{organization}/{project}/pipeline/run_post for http method type POST +# RoostTestHash=eafb1cdffb +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_provider_organization_project_pipeline_run.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_trigger_pipeline_run(api_client, config_test_data, scenario_case): + """ + Test the /project/{provider}/{organization}/{project}/pipeline/run endpoint. + """ + # Prepare endpoint and request data + endpoint = f"project/{scenario_case['provider']}/{scenario_case['organization']}/{scenario_case['project']}/pipeline/run" + method = 'POST' + request_data = { + "definition_id": scenario_case.get("definition_id", config_test_data['pipeline_definition_id']) + } + + # Add optional fields if present + if 'config' in scenario_case: + request_data['config'] = scenario_case['config'] + if 'checkout' in scenario_case: + request_data['checkout'] = scenario_case['checkout'] + if 'parameters' in scenario_case: + request_data['parameters'] = scenario_case['parameters'] + + # Validate request schema + validator.validate_json(request_data, 'PipelineRunRequest') + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, method, str(scenario_case['statusCode']), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + + # Assert status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Additional response validation based on status code + if response.status_code == 201: + response_data = response.json() + assert 'state' in response_data, "Missing 'state' in response" + assert 'created_at' in response_data, "Missing 'created_at' in response" + assert 'number' in response_data, "Missing 'number' in response" + assert 'id' in response_data, "Missing 'id' in response" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_trigger_pipeline_run_invalid_auth(api_client, scenario_case): + """ + Test the /project/{provider}/{organization}/{project}/pipeline/run endpoint with invalid authentication. + """ + endpoint = f"project/{scenario_case['provider']}/{scenario_case['organization']}/{scenario_case['project']}/pipeline/run" + method = 'POST' + request_data = { + "definition_id": scenario_case.get("definition_id", "invalid-id") + } + + # Make API request with invalid token + response = api_client.post(endpoint, json=request_data, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, method, '401', response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + + # Assert status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Assert error message + response_data = response.json() + assert response_data['message'] == "Invalid token provided.", "Unexpected error message" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_trigger_pipeline_run_missing_auth(api_client, scenario_case): + """ + Test the /project/{provider}/{organization}/{project}/pipeline/run endpoint with missing authentication. + """ + endpoint = f"project/{scenario_case['provider']}/{scenario_case['organization']}/{scenario_case['project']}/pipeline/run" + method = 'POST' + request_data = { + "definition_id": scenario_case.get("definition_id", "invalid-id") + } + + # Make API request without token + response = api_client.post(endpoint, json=request_data, headers={}) + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, method, '401', response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + + # Assert status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Assert error message + response_data = response.json() + assert response_data['message'] == "Invalid token provided.", "Unexpected error message" diff --git a/tests/CIRCLECI_API/test_project_provider_organization_project_post.py b/tests/CIRCLECI_API/test_project_provider_organization_project_post.py new file mode 100644 index 00000000..d20b0f8d --- /dev/null +++ b/tests/CIRCLECI_API/test_project_provider_organization_project_post.py @@ -0,0 +1,101 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{provider}/{organization}/{project}_post for http method type POST +# RoostTestHash=c356800e1b +# +# + +# ********RoostGPT******** +""" +Pytest test suite for CircleCI API endpoint /project/{provider}/{organization}/{project} + +This test suite covers: +- Successful project creation with required and optional fields. +- Various authentication scenarios. +- Response validation against OpenAPI spec. +- Error scenarios including invalid credentials, missing resources, and rate limits. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `config.yml` in the same directory with appropriate values. +- Ensure `project_provider_organization_project.json` is in the same directory for test data. + +Run the tests with: +pytest test_project_api.py +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_provider_organization_project.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_project_success(api_client, config_test_data, scenario_case): + """ + Test successful project creation with required and optional fields. + """ + endpoint = f"/project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}" + payload = scenario_case.get('advanced', {}) + + # Validate request payload + validator.validate_json(payload, 'AdvancedSettings') + + response = api_client.post(endpoint, json=payload) + + # Validate response + assert response.status_code == scenario_case['statusCode'] + validation_result = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("auth_header", [ + pytest.param("InvalidToken", id="invalid_token"), + pytest.param("", id="missing_token"), +]) +def test_create_project_auth_errors(api_client, config_test_data, auth_header): + """ + Test project creation with invalid and missing authentication. + """ + endpoint = f"/project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}" + headers = {'Authorization': f"Bearer {auth_header}"} + payload = {"advanced": {"autocancel_builds": True}} + + response = api_client.post(endpoint, json=payload, headers=headers) + + # Validate response + assert response.status_code == 401 + validation_result = validator.validate_schema_by_response(endpoint, 'POST', '401', response) + assert validation_result['valid'], validation_result.get('message', '') + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_project_error_handling(api_client, config_test_data, scenario_case): + """ + Test error scenarios for project creation. + """ + endpoint = f"/project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}" + payload = scenario_case.get('advanced', {}) + + # Simulate different error scenarios + if scenario_case['statusCode'] == 400: + payload['unexpected_field'] = True # Introduce unexpected field to trigger 400 + + response = api_client.post(endpoint, json=payload) + + # Validate response + assert response.status_code == scenario_case['statusCode'] + validation_result = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert validation_result['valid'], validation_result.get('message', '') diff --git a/tests/CIRCLECI_API/test_project_provider_organization_project_settings_get.py b/tests/CIRCLECI_API/test_project_provider_organization_project_settings_get.py new file mode 100644 index 00000000..f0a743db --- /dev/null +++ b/tests/CIRCLECI_API/test_project_provider_organization_project_settings_get.py @@ -0,0 +1,101 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{provider}/{organization}/{project}/settings_get for http method type GET +# RoostTestHash=bc8bcc46b5 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load API spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_provider_organization_project_settings.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_settings(api_client, config_test_data, scenario_case): + """ + Test the /project/{provider}/{organization}/{project}/settings endpoint. + """ + # Prepare endpoint and headers + endpoint = f"project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}/settings" + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + # Make API request + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks based on scenario + if response.status_code == 200: + response_data = response.json() + assert 'advanced' in response_data, "Response missing 'advanced' key" + for key, value in scenario_case['advanced'].items(): + if key in response_data['advanced']: + assert response_data['advanced'][key] == value, f"Expected {key} to be {value}, got {response_data['advanced'][key]}" + +@pytest.mark.parametrize("auth_header", [ + ('Bearer invalid_token'), + ('Bearer expired_token'), + ('') +], ids=["invalid_token", "expired_token", "missing_token"]) +def test_get_project_settings_auth_errors(api_client, config_test_data, auth_header): + """ + Test authentication errors for the /project/{provider}/{organization}/{project}/settings endpoint. + """ + endpoint = f"project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}/settings" + headers = {'Authorization': auth_header} + + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code in [401, 403], f"Expected 401 or 403, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Check error message + response_data = response.json() + assert 'message' in response_data, "Response missing 'message' key" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_project_settings_not_found(api_client, config_test_data, scenario_case): + """ + Test 404 Not Found for the /project/{provider}/{organization}/{project}/settings endpoint. + """ + endpoint = f"project/{config_test_data['provider']}/nonexistent_org/nonexistent_proj/settings" + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 404, f"Expected 404, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Check error message + response_data = response.json() + assert 'message' in response_data, "Response missing 'message' key" diff --git a/tests/CIRCLECI_API/test_project_provider_organization_project_settings_patch.py b/tests/CIRCLECI_API/test_project_provider_organization_project_settings_patch.py new file mode 100644 index 00000000..ee749c90 --- /dev/null +++ b/tests/CIRCLECI_API/test_project_provider_organization_project_settings_patch.py @@ -0,0 +1,89 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /project/{provider}/{organization}/{project}/settings_patch for http method type PATCH +# RoostTestHash=eb2991fea4 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'project_provider_organization_project_settings.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_patch_project_settings(api_client, config_test_data, scenario_case): + """ + Test the PATCH /project/{provider}/{organization}/{project}/settings endpoint. + """ + # Prepare endpoint and request data + endpoint = f"/project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}/settings" + request_data = scenario_case.get('advanced', {}) + expected_status_code = scenario_case['statusCode'] + + # Validate request schema + validation_result = validator.validate_json(request_data, 'patchProjectSettings') + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make the API request + response = api_client.patch(endpoint, json=request_data) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'PATCH', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("auth_scenario", ["valid", "invalid", "missing"]) +def test_patch_project_settings_auth(api_client, config_test_data, auth_scenario): + """ + Test authentication scenarios for the PATCH /project/{provider}/{organization}/{project}/settings endpoint. + """ + endpoint = f"/project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}/settings" + request_data = {"advanced": {"autocancel_builds": True}} + + if auth_scenario == "valid": + response = api_client.patch(endpoint, json=request_data) + assert response.status_code == 200 + elif auth_scenario == "invalid": + response = api_client.patch(endpoint, json=request_data, headers={"Authorization": "Bearer invalid_token"}) + assert response.status_code == 401 + elif auth_scenario == "missing": + response = api_client.patch(endpoint, json=request_data, headers={}) + assert response.status_code == 403 + +@pytest.mark.parametrize("error_case", [ + {"advanced": {"autocancel_builds": "not_a_boolean"}, "expected_status": 400}, + {"advanced": {"unknown_field": True}, "expected_status": 400}, + {"advanced": {}, "expected_status": 400}, +]) +def test_patch_project_settings_error_cases(api_client, config_test_data, error_case): + """ + Test error scenarios for the PATCH /project/{provider}/{organization}/{project}/settings endpoint. + """ + endpoint = f"/project/{config_test_data['provider']}/{config_test_data['organization']}/{config_test_data['project']}/settings" + request_data = error_case['advanced'] + expected_status_code = error_case['expected_status'] + + response = api_client.patch(endpoint, json=request_data) + assert response.status_code == expected_status_code + + response_validation = validator.validate_schema_by_response(endpoint, 'PATCH', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_get.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_get.py new file mode 100644 index 00000000..21717540 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_get.py @@ -0,0 +1,105 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions_get for http method type GET +# RoostTestHash=730d8c6d11 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load API specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'projects_project_id_pipeline-definitions.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i['scenario']}" for i in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipeline_definitions(api_client, config_test_data, scenario_case): + """ + Test the /projects/{project_id}/pipeline-definitions endpoint. + """ + # Prepare endpoint and headers + endpoint = f"/projects/{scenario_case['project_id']}/pipeline-definitions" + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + # Make the API request + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=endpoint, + method='GET', + status_code=str(scenario_case['statusCode']), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipeline_definitions_invalid_auth(api_client, scenario_case): + """ + Test the /projects/{project_id}/pipeline-definitions endpoint with invalid authentication. + """ + # Prepare endpoint and headers with invalid token + endpoint = f"/projects/{scenario_case['project_id']}/pipeline-definitions" + headers = {'Authorization': "Bearer invalid_token"} + + # Make the API request + response = api_client.get(endpoint, headers=headers) + + # Validate response status code for invalid auth + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=endpoint, + method='GET', + status_code='401', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipeline_definitions_missing_auth(api_client, scenario_case): + """ + Test the /projects/{project_id}/pipeline-definitions endpoint with missing authentication. + """ + # Prepare endpoint without headers + endpoint = f"/projects/{scenario_case['project_id']}/pipeline-definitions" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code for missing auth + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=endpoint, + method='GET', + status_code='401', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_delete.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_delete.py new file mode 100644 index 00000000..10cf793c --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_delete.py @@ -0,0 +1,78 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}_delete for http method type DELETE +# RoostTestHash=cefe6b9392 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the DELETE /projects/{project_id}/pipeline-definitions/{pipeline_definition_id} endpoint. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. +- Place the `projects_project_id_pipeline-definitions_pipeline_.json` file in the same directory. + +Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'projects_project_id_pipeline-definitions_pipeline_.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['statusCode']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_pipeline_definition(api_client, config_test_data, scenario_case): + """ + Test DELETE /projects/{project_id}/pipeline-definitions/{pipeline_definition_id} endpoint. + """ + project_id = scenario_case.get('project_id', config_test_data['project_id']) + pipeline_definition_id = scenario_case.get('pipeline_definition_id', config_test_data['pipeline_definition_id']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}" + + # Make the DELETE request + try: + response = api_client.delete(endpoint) + except Exception as e: + if expected_status_code == 500: + pytest.skip(f"Skipping test due to expected server error: {e}") + else: + raise + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks based on scenario + if expected_status_code == 200: + assert 'message' in response.json(), "Response JSON should contain 'message' field" + elif expected_status_code == 400: + assert response.json().get('message') == "Unexpected request body provided.", "Expected specific error message for 400 status" + elif expected_status_code == 401: + assert 'message' in response.json(), "Response JSON should contain 'message' field for 401 status" + elif expected_status_code == 404: + assert 'message' in response.json(), "Response JSON should contain 'message' field for 404 status" + elif expected_status_code == 500: + assert response.json().get('message') == "Internal server error.", "Expected specific error message for 500 status" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_get.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_get.py new file mode 100644 index 00000000..b75c5f5b --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_get.py @@ -0,0 +1,87 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}_get for http method type GET +# RoostTestHash=127eab6554 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI API endpoint: /projects/{project_id}/pipeline-definitions/{pipeline_definition_id} + +This test suite covers: +- Successful response scenarios +- Client error scenarios +- Security schema testing with valid and invalid credentials +- Schema validation using SwaggerSchemaValidator + +Instructions: +- Ensure conftest.py and validator.py are in the same directory as this test file. +- Use pytest to execute the tests. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / "projects_project_id_pipeline-definitions_pipeline_.json" +with open(_endpoint_data_path, "r") as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +# Initialize SwaggerSchemaValidator +swagger_validator = SwaggerSchemaValidator(_here / "api.json") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_definition(api_client, config_test_data, scenario_case): + """ + Test the GET /projects/{project_id}/pipeline-definitions/{pipeline_definition_id} endpoint. + """ + project_id = scenario_case.get("project_id", config_test_data["project_id"]) + pipeline_definition_id = scenario_case.get("pipeline_definition_id", config_test_data["pipeline_definition_id"]) + expected_status_code = scenario_case["statusCode"] + + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}" + + # Make the API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint, "GET", str(expected_status_code), response + ) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_pipeline_definition_invalid_auth(api_client, scenario_case): + """ + Test the GET /projects/{project_id}/pipeline-definitions/{pipeline_definition_id} endpoint with invalid authentication. + """ + project_id = scenario_case.get("project_id", "invalid_project_id") + pipeline_definition_id = scenario_case.get("pipeline_definition_id", "invalid_pipeline_definition_id") + expected_status_code = 401 + + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}" + + # Make the API request with invalid token + response = api_client.get(endpoint, headers={"Authorization": "Bearer invalid_token"}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response( + endpoint, "GET", str(expected_status_code), response + ) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_patch.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_patch.py new file mode 100644 index 00000000..24c74308 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_patch.py @@ -0,0 +1,120 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}_patch for http method type PATCH +# RoostTestHash=bc5447186a +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the CircleCI API endpoint for updating pipeline definitions. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory as this test file. +- Ensure `config.yml` is properly configured with the necessary API host and authentication details. +- Place `projects_project_id_pipeline-definitions_pipeline_.json` in the same directory for test data. + +Run tests using pytest: +$ pytest -v + +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'projects_project_id_pipeline-definitions_pipeline_.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"case_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_pipeline_definition(api_client, config_test_data, scenario_case): + """ + Test updating a pipeline definition with various scenarios. + """ + # Extract data from scenario + project_id = scenario_case['project_id'] + pipeline_definition_id = scenario_case['pipeline_definition_id'] + name = scenario_case.get('name') + description = scenario_case.get('description', '') + config_source = scenario_case['config_source'] + checkout_source = scenario_case.get('checkout_source', {}) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}" + + # Construct request payload + payload = { + "name": name, + "description": description, + "config_source": config_source + } + if checkout_source: + payload["checkout_source"] = checkout_source + + # Validate request payload + request_validation = validator.validate_json(payload, "PipelineDefinitionUpdateRequest") + assert request_validation['valid'], f"Request validation failed: {request_validation['message']}" + + # Make API request + response = api_client.patch(endpoint, json=payload) + + # Assert response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'PATCH', str(expected_status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_pipeline_definition_invalid_auth(api_client, scenario_case): + """ + Test updating a pipeline definition with invalid authentication. + """ + # Extract data from scenario + project_id = scenario_case['project_id'] + pipeline_definition_id = scenario_case['pipeline_definition_id'] + name = scenario_case.get('name') + description = scenario_case.get('description', '') + config_source = scenario_case['config_source'] + checkout_source = scenario_case.get('checkout_source', {}) + + # Construct endpoint + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}" + + # Construct request payload + payload = { + "name": name, + "description": description, + "config_source": config_source + } + if checkout_source: + payload["checkout_source"] = checkout_source + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.patch(endpoint, json=payload, headers=headers) + + # Assert response status code + assert response.status_code == 401, f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'PATCH', '401', response) + assert response_validation['valid'], f"Response validation failed: {response_validation['message']}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_get.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_get.py new file mode 100644 index 00000000..e152104e --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_get.py @@ -0,0 +1,85 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers_get for http method type GET +# RoostTestHash=a23b6220d6 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `projects_project_id_pipeline-definitions_pipeline_.json` in the same directory as this test file. +- Ensure `config.yml` is correctly configured with necessary API host and authentication details. + +Run the tests using pytest: +$ pytest test_api.py +""" + +import pytest +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load API spec and test data +_API_SPEC_PATH = Path(__file__).parent / 'api.json' +_TEST_DATA_FILENAME = 'projects_project_id_pipeline-definitions_pipeline_.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / _TEST_DATA_FILENAME + +# Initialize SwaggerSchemaValidator +validator = SwaggerSchemaValidator(_API_SPEC_PATH) + +# Load endpoint test data +def _load_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipeline_definition_triggers(api_client, config_test_data, scenario_case): + """ + Test the /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers endpoint. + """ + # Prepare endpoint and parameters + project_id = scenario_case.get('project_id', config_test_data['project_id']) + pipeline_definition_id = scenario_case.get('pipeline_definition_id', config_test_data['pipeline_definition_id']) + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Expected {scenario_case['statusCode']} but got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_list_pipeline_definition_triggers_invalid_auth(api_client, scenario_case): + """ + Test the /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers endpoint with invalid authentication. + """ + # Prepare endpoint and parameters + project_id = scenario_case.get('project_id', 'invalid_project_id') + pipeline_definition_id = scenario_case.get('pipeline_definition_id', 'invalid_pipeline_definition_id') + endpoint = f"/projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers" + + # Make API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 but got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_post.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_post.py new file mode 100644 index 00000000..8b81789d --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_pipeline_definition_id_triggers_post.py @@ -0,0 +1,96 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers_post for http method type POST +# RoostTestHash=9a06f7601b +# +# + +# ********RoostGPT******** +""" +Pytest test suite for API endpoint: /projects/{project_id}/pipeline-definitions/{pipeline_definition_id}/triggers + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory as this test file. +- Ensure `config.yml` is configured with the correct API host and authentication details. +- Place `projects_project_id_pipeline-definitions_pipeline_.json` in the same directory for test data. + +Run the tests using pytest: +$ pytest test_api.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / "projects_project_id_pipeline-definitions_pipeline_.json" +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +# Initialize SwaggerSchemaValidator +swagger_validator = SwaggerSchemaValidator(_here / "api.json") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_trigger(api_client, config_test_data, scenario_case): + """ + Test the creation of a trigger for a pipeline definition. + """ + # Prepare endpoint and request data + endpoint = f"/projects/{scenario_case['project_id']}/pipeline-definitions/{scenario_case['pipeline_definition_id']}/triggers" + request_data = { + "event_source": scenario_case.get("event_source"), + "event_preset": scenario_case.get("event_preset"), + "checkout_ref": scenario_case.get("checkout_ref"), + "config_ref": scenario_case.get("config_ref"), + "event_name": scenario_case.get("event_name"), + "disabled": scenario_case.get("disabled") + } + # Remove None values + request_data = {k: v for k, v in request_data.items() if v is not None} + + # Validate request schema + validation_result = swagger_validator.validate_json(request_data, "CreateTriggerRequest") + assert validation_result["valid"], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response schema + response_validation = swagger_validator.validate_schema_by_response(endpoint, "post", str(scenario_case['statusCode']), response) + assert response_validation["valid"], f"Response validation failed: {response_validation.get('message')}" + + # Assert status code + assert response.status_code == scenario_case['statusCode'], f"Expected status code {scenario_case['statusCode']}, got {response.status_code}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_trigger_invalid_auth(api_client, scenario_case): + """ + Test the creation of a trigger with invalid authentication. + """ + # Prepare endpoint and request data + endpoint = f"/projects/{scenario_case['project_id']}/pipeline-definitions/{scenario_case['pipeline_definition_id']}/triggers" + request_data = { + "event_source": scenario_case.get("event_source"), + "event_preset": scenario_case.get("event_preset"), + "checkout_ref": scenario_case.get("checkout_ref"), + "config_ref": scenario_case.get("config_ref"), + "event_name": scenario_case.get("event_name"), + "disabled": scenario_case.get("disabled") + } + # Remove None values + request_data = {k: v for k, v in request_data.items() if v is not None} + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.post(endpoint, json=request_data, headers=headers) + + # Assert status code for invalid auth + assert response.status_code == 401, f"Expected status code 401, got {response.status_code}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_post.py b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_post.py new file mode 100644 index 00000000..76000ca6 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_pipeline-definitions_post.py @@ -0,0 +1,95 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/pipeline-definitions_post for http method type POST +# RoostTestHash=8550872bf8 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI API endpoint: /projects/{project_id}/pipeline-definitions + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Place `projects_project_id_pipeline-definitions.json` in the same directory. +- Update `config.yml` with valid API host and authentication details. + +Run the tests using pytest: +$ pytest test_pipeline_definitions.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'projects_project_id_pipeline-definitions.json' +with open(_endpoint_data_path) as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}-{case['project_id']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_pipeline_definition(api_client, config_test_data, scenario_case): + """ + Test the creation of pipeline definitions for various scenarios. + """ + project_id = scenario_case.get('project_id', config_test_data['project_id']) + endpoint = f"/projects/{project_id}/pipeline-definitions" + + # Prepare request payload + payload = { + "name": scenario_case.get('name', config_test_data['name']), + "config_source": scenario_case.get('config_source', {}), + "checkout_source": scenario_case.get('checkout_source', {}) + } + + # Validate request payload + validation_result = validator.validate_json(payload, 'PipelineDefinitionRequest') + assert validation_result['valid'], f"Request validation failed: {validation_result['message']}" + + # Make API request + response = api_client.post(endpoint, json=payload) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'post', str(response.status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_pipeline_definition_invalid_auth(api_client, scenario_case): + """ + Test the creation of pipeline definitions with invalid authentication. + """ + project_id = scenario_case.get('project_id', 'invalid-project-id') + endpoint = f"/projects/{project_id}/pipeline-definitions" + + # Prepare request payload + payload = { + "name": scenario_case.get('name', 'Invalid Pipeline'), + "config_source": scenario_case.get('config_source', {}), + "checkout_source": scenario_case.get('checkout_source', {}) + } + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.post(endpoint, json=payload, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'post', '401', response) + assert validation_result['valid'], f"Response validation failed: {validation_result['message']}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_rollback_post.py b/tests/CIRCLECI_API/test_projects_project_id_rollback_post.py new file mode 100644 index 00000000..f698cbf6 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_rollback_post.py @@ -0,0 +1,104 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/rollback_post for http method type POST +# RoostTestHash=64786c643b +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /projects/{project_id}/rollback endpoint. + +This test suite covers: +- All possible response status codes. +- Security schema testing with valid and invalid credentials. +- Request and response schema validation. +- Various scenarios using parameterized tests. + +Instructions: +- Ensure conftest.py and validator.py are in the same directory. +- Use pytest to run the tests. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'projects_project_id_rollback.json' +with open(_endpoint_data_path, 'r') as f: + ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = ENDPOINT_TEST_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(ENDPOINT_TEST_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_rollback_project(api_client, config_test_data, scenario_case): + """ + Test the rollback project endpoint with various scenarios. + """ + # Prepare endpoint and request data + endpoint = f"/projects/{scenario_case['project_id']}/rollback" + request_data = { + "component_name": scenario_case.get("component_name", config_test_data.get("component_name")), + "current_version": scenario_case.get("current_version", config_test_data.get("current_version")), + "target_version": scenario_case.get("target_version", config_test_data.get("target_version")) + } + + # Add optional fields if present + if "environment_name" in scenario_case: + request_data["environment_name"] = scenario_case["environment_name"] + if "namespace" in scenario_case: + request_data["namespace"] = scenario_case["namespace"] + if "parameters" in scenario_case: + request_data["parameters"] = scenario_case["parameters"] + if "reason" in scenario_case: + request_data["reason"] = scenario_case["reason"] + + # Validate request schema + request_validation = validator.validate_json(request_data, "RollbackRequest") + assert request_validation["valid"], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response status code + assert response.status_code == scenario_case["statusCode"], f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, "post", str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_rollback_project_invalid_auth(api_client, scenario_case): + """ + Test the rollback project endpoint with invalid authentication. + """ + endpoint = f"/projects/{scenario_case['project_id']}/rollback" + request_data = { + "component_name": scenario_case.get("component_name", "default_component"), + "current_version": scenario_case.get("current_version", "0.0.1"), + "target_version": scenario_case.get("target_version", "0.0.2") + } + + # Simulate invalid authentication + api_client.auth['api_key_header'] = "InvalidToken" + + # Make API request + response = api_client.post(endpoint, json=request_data) + + # Validate response status code for unauthorized access + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, "post", "401", response) + assert response_validation["valid"], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_delete.py b/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_delete.py new file mode 100644 index 00000000..1404d7a1 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_delete.py @@ -0,0 +1,97 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/triggers/{trigger_id}_delete for http method type DELETE +# RoostTestHash=c8ea03be61 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the API endpoint /projects/{project_id}/triggers/{trigger_id} + +Instructions: +- Ensure you have pytest and requests installed in your environment. +- Place this file in the same directory as the conftest.py and validator.py files. +- Run the tests using the command: pytest .py + +This test suite covers: +- Successful deletion of a trigger. +- Various authentication scenarios. +- Handling of different response status codes. +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Load the API spec for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +TEST_DATA_FILENAME = 'projects_project_id_triggers_trigger_id.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_trigger(api_client, config_test_data, scenario_case): + """ + Test the DELETE /projects/{project_id}/triggers/{trigger_id} endpoint. + """ + project_id = scenario_case.get('project_id', config_test_data['project_id']) + trigger_id = scenario_case.get('trigger_id', config_test_data['trigger_id']) + expected_status_code = scenario_case['statusCode'] + + endpoint = f"/projects/{project_id}/triggers/{trigger_id}" + + # Validate request schema before sending + request_data = {} + validation_result = validator.validate_json(request_data, "deleteTriggerRequest") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make the API request + response = api_client.delete(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("auth_header", [ + pytest.param("InvalidToken", id="invalid_token"), + pytest.param("", id="missing_token"), +]) +def test_delete_trigger_authentication(api_client, config_test_data, auth_header): + """ + Test authentication scenarios for the DELETE /projects/{project_id}/triggers/{trigger_id} endpoint. + """ + project_id = config_test_data['project_id'] + trigger_id = config_test_data['trigger_id'] + + endpoint = f"/projects/{project_id}/triggers/{trigger_id}" + + # Override the authorization header + headers = {'Authorization': f"Bearer {auth_header}"} + + # Make the API request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', '401', response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_get.py b/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_get.py new file mode 100644 index 00000000..7cdc68e7 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_get.py @@ -0,0 +1,68 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/triggers/{trigger_id}_get for http method type GET +# RoostTestHash=c5b2c3108e +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'projects_project_id_triggers_trigger_id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"Scenario: {case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_trigger(api_client, config_test_data, scenario_case): + """ + Test the GET /projects/{project_id}/triggers/{trigger_id} endpoint. + """ + # Setup + project_id = scenario_case.get('project_id', config_test_data['project_id']) + trigger_id = scenario_case.get('trigger_id', config_test_data['trigger_id']) + endpoint = f"/projects/{project_id}/triggers/{trigger_id}" + + # Execute + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_trigger_invalid_auth(api_client, scenario_case): + """ + Test the GET /projects/{project_id}/triggers/{trigger_id} endpoint with invalid authentication. + """ + # Setup + project_id = scenario_case.get('project_id', 'invalid-project-id') + trigger_id = scenario_case.get('trigger_id', 'invalid-trigger-id') + endpoint = f"/projects/{project_id}/triggers/{trigger_id}" + + # Execute + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', '401', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_patch.py b/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_patch.py new file mode 100644 index 00000000..43ceff34 --- /dev/null +++ b/tests/CIRCLECI_API/test_projects_project_id_triggers_trigger_id_patch.py @@ -0,0 +1,65 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /projects/{project_id}/triggers/{trigger_id}_patch for http method type PATCH +# RoostTestHash=eb5872453f +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the API specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'projects_project_id_triggers_trigger_id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_trigger(api_client, config_test_data, scenario_case): + """ + Test the /projects/{project_id}/triggers/{trigger_id} endpoint with various scenarios. + """ + project_id = scenario_case.get('project_id', config_test_data['project_id']) + trigger_id = scenario_case.get('trigger_id', config_test_data['trigger_id']) + endpoint = f"/projects/{project_id}/triggers/{trigger_id}" + + # Prepare request body + request_body = { + "event_name": scenario_case.get("event_name"), + "event_preset": scenario_case.get("event_preset"), + "checkout_ref": scenario_case.get("checkout_ref"), + "config_ref": scenario_case.get("config_ref"), + "disabled": scenario_case.get("disabled"), + "event_source": scenario_case.get("event_source") + } + # Remove None values + request_body = {k: v for k, v in request_body.items() if v is not None} + + # Validate request schema + validation_result = validator.validate_json(request_body, "UpdateTriggerRequest") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make the API request + response = api_client.patch(endpoint, json=request_body) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'PATCH', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" diff --git a/tests/CIRCLECI_API/test_schedule_schedule-id_delete.py b/tests/CIRCLECI_API/test_schedule_schedule-id_delete.py new file mode 100644 index 00000000..bebe9cf8 --- /dev/null +++ b/tests/CIRCLECI_API/test_schedule_schedule-id_delete.py @@ -0,0 +1,60 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /schedule/{schedule-id}_delete for http method type DELETE +# RoostTestHash=7f9487211b +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'schedule_schedule-id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i, _ in enumerate(_ENDPOINT_DATA)] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_schedule_by_id(api_client, config_test_data, scenario_case): + """ + Test the DELETE /schedule/{schedule-id} endpoint. + """ + schedule_id = scenario_case.get("schedule-id", config_test_data['schedule-id']) + expected_status_code = scenario_case['statusCode'] + endpoint = f"/schedule/{schedule_id}" + + # Make the DELETE request + response = api_client.delete(endpoint) + + # Validate the response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate the response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" + + # Additional checks based on status code + if response.status_code == 200: + response_data = response.json() + assert 'message' in response_data, "Response does not contain 'message'" + elif response.status_code != 200: + pytest.skip(f"Skipping non-200 status code: {response.status_code}") + +# Instructions for running the tests +""" +To run the tests, use the following command: +pytest -v test_api.py +""" diff --git a/tests/CIRCLECI_API/test_schedule_schedule-id_get.py b/tests/CIRCLECI_API/test_schedule_schedule-id_get.py new file mode 100644 index 00000000..d50d7c62 --- /dev/null +++ b/tests/CIRCLECI_API/test_schedule_schedule-id_get.py @@ -0,0 +1,81 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /schedule/{schedule-id}_get for http method type GET +# RoostTestHash=b8ae91f41e +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load API spec for validation +API_SPEC_PATH = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data +_here = Path(__file__).resolve().parent +_ENDPOINT_DATA_PATH = _here / 'schedule_schedule-id.json' +with open(_ENDPOINT_DATA_PATH, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=[str(i) for i in range(len(_ENDPOINT_DATA))]) +def test_get_schedule_by_id(api_client, config_test_data, scenario_case): + """ + Test the GET /schedule/{schedule-id} endpoint. + """ + schedule_id = scenario_case.get("schedule-id", config_test_data["schedule-id"]) + expected_status_code = scenario_case["statusCode"] + + # Construct endpoint + endpoint = f"/schedule/{schedule_id}" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=[str(i) for i in range(len(_ENDPOINT_DATA))]) +def test_get_schedule_by_id_invalid_auth(api_client, scenario_case): + """ + Test the GET /schedule/{schedule-id} endpoint with invalid authentication. + """ + schedule_id = scenario_case.get("schedule-id", "invalid-id") + endpoint = f"/schedule/{schedule_id}" + + # Make API request with invalid token + response = api_client.get(endpoint, headers={"Authorization": "Bearer invalid_token"}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _ENDPOINT_DATA, ids=[str(i) for i in range(len(_ENDPOINT_DATA))]) +def test_get_schedule_by_id_missing_auth(api_client, scenario_case): + """ + Test the GET /schedule/{schedule-id} endpoint with missing authentication. + """ + schedule_id = scenario_case.get("schedule-id", "invalid-id") + endpoint = f"/schedule/{schedule_id}" + + # Make API request without token + response = api_client.get(endpoint, headers={}) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_schedule_schedule-id_patch.py b/tests/CIRCLECI_API/test_schedule_schedule-id_patch.py new file mode 100644 index 00000000..0884e005 --- /dev/null +++ b/tests/CIRCLECI_API/test_schedule_schedule-id_patch.py @@ -0,0 +1,106 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /schedule/{schedule-id}_patch for http method type PATCH +# RoostTestHash=4e3e62a75c +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the CircleCI API's schedule update endpoint. + +This suite tests the /schedule/{schedule-id} endpoint using various scenarios +defined in the schedule_schedule-id.json file. The tests cover successful updates, +authentication issues, and validation of request and response schemas. + +Setup: +- Ensure the config.yml file is correctly configured with the API host and authentication details. +- Place the schedule_schedule-id.json file in the same directory as this test file. + +Run the tests using the command: +pytest test_schedule_update.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'schedule_schedule-id.json' +with open(_endpoint_data_path, 'r') as file: + _ENDPOINT_DATA = json.load(file) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"case_{i}" for i, _ in enumerate(_ENDPOINT_DATA)] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_schedule(api_client, config_test_data, scenario_case): + """ + Test the update schedule endpoint with various scenarios. + """ + schedule_id = scenario_case.get("schedule-id") + endpoint = f"/schedule/{schedule_id}" + method = 'PATCH' + + # Prepare request data + request_data = { + "name": scenario_case.get("name"), + "timetable": scenario_case.get("timetable"), + "description": scenario_case.get("description"), + } + if "parameters" in scenario_case: + request_data["parameters"] = scenario_case["parameters"] + + # Validate request schema + validation_result = validator.validate_json(request_data, "UpdateScheduleParameters") + assert validation_result["valid"], f"Request validation failed: {validation_result['message']}" + + # Make API request + response = api_client.patch(endpoint, json=request_data) + + # Validate response status code + expected_status_code = scenario_case.get("statusCode", 200) + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, method, str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_schedule_invalid_auth(api_client, scenario_case): + """ + Test the update schedule endpoint with invalid authentication. + """ + schedule_id = scenario_case.get("schedule-id") + endpoint = f"/schedule/{schedule_id}" + method = 'PATCH' + + # Prepare request data + request_data = { + "name": scenario_case.get("name"), + "timetable": scenario_case.get("timetable"), + "description": scenario_case.get("description"), + } + if "parameters" in scenario_case: + request_data["parameters"] = scenario_case["parameters"] + + # Make API request with invalid auth + invalid_auth = {"Authorization": "Bearer invalid_token"} + response = api_client.patch(endpoint, json=request_data, headers=invalid_auth) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, method, str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" diff --git a/tests/CIRCLECI_API/test_user_id_get.py b/tests/CIRCLECI_API/test_user_id_get.py new file mode 100644 index 00000000..981a0673 --- /dev/null +++ b/tests/CIRCLECI_API/test_user_id_get.py @@ -0,0 +1,88 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /user/{id}_get for http method type GET +# RoostTestHash=801f4cbd76 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the User API endpoint. + +This test suite validates the /user/{id} endpoint using the pytest framework. +It covers various scenarios including successful responses, authentication errors, +and schema validation. The test data is loaded from a JSON file and the API +specification is validated using the SwaggerSchemaValidator. + +Instructions for running the tests: +1. Ensure pytest is installed in your environment. +2. Place the user_id.json file in the same directory as this test file. +3. Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'user_id.json' +with open(_endpoint_data_path, 'r') as f: + ENDPOINT_TEST_DATA = json.load(f) + +# Load API spec for validation +api_spec_path = _here / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Reusable parametrize args +_PARAM_CASES = ENDPOINT_TEST_DATA +_PARAM_IDS = [case['scenario'] for case in ENDPOINT_TEST_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_user(api_client, config_test_data, scenario_case): + """ + Test the /user/{id} endpoint for various scenarios. + + This test checks the response status code and validates the response schema + against the OpenAPI specification. + """ + user_id = scenario_case.get('id', config_test_data['id']) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint + endpoint = f"/user/{user_id}" + + # Make API request + response = api_client.get(endpoint) + + # Assert status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_user_invalid_auth(api_client, scenario_case): + """ + Test the /user/{id} endpoint with invalid authentication. + + This test checks that the API returns the correct error response when + invalid authentication is provided. + """ + user_id = scenario_case.get('id', 'invalid-id') + endpoint = f"/user/{user_id}" + + # Make API request with invalid token + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.get(endpoint, headers=headers) + + # Assert status code is not 2xx + assert response.status_code != 200, f"Expected non-200 status code, got {response.status_code}" + + # Validate error response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message', '')}" diff --git a/tests/CIRCLECI_API/test_webhook_get.py b/tests/CIRCLECI_API/test_webhook_get.py new file mode 100644 index 00000000..7df5b828 --- /dev/null +++ b/tests/CIRCLECI_API/test_webhook_get.py @@ -0,0 +1,93 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /webhook_get for http method type GET +# RoostTestHash=7b184769d5 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'webhook.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_webhooks(api_client, config_test_data, scenario_case): + """ + Test the GET /webhook endpoint with various scenarios. + """ + # Extract test data + scope_id = scenario_case.get("scope-id", config_test_data.get("projectID")) + scope_type = scenario_case.get("scope-type", "project") + expected_status_code = scenario_case.get("statusCode", 200) + + # Prepare request parameters + params = { + "scope-id": scope_id, + "scope-type": scope_type + } + + # Make the API request + response = api_client.get("/webhook", params=params) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/webhook", "get", str(expected_status_code), response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" + + # Additional checks for successful response + if expected_status_code == 200: + response_data = response.json() + assert "items" in response_data, "Response missing 'items'" + assert isinstance(response_data["items"], list), "'items' should be a list" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_webhooks_invalid_auth(api_client, scenario_case): + """ + Test the GET /webhook endpoint with invalid authentication. + """ + # Extract test data + scope_id = scenario_case.get("scope-id", "invalid-scope-id") + scope_type = scenario_case.get("scope-type", "project") + + # Prepare request parameters + params = { + "scope-id": scope_id, + "scope-type": scope_type + } + + # Use invalid token for this test + invalid_headers = {'Authorization': 'Bearer invalid_token'} + + # Make the API request + response = api_client.get("/webhook", headers=invalid_headers, params=params) + + # Validate response status code + assert response.status_code == 401, f"Expected 401 Unauthorized, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response("/webhook", "get", "default", response) + assert validation_result["valid"], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_webhook_post.py b/tests/CIRCLECI_API/test_webhook_post.py new file mode 100644 index 00000000..069383fd --- /dev/null +++ b/tests/CIRCLECI_API/test_webhook_post.py @@ -0,0 +1,130 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /webhook_post for http method type POST +# RoostTestHash=b6ef5106d0 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the /webhook endpoint of the API. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory as this test file. +- Ensure `webhook.json` is in the same directory as this test file. +- Ensure `config.yml` is correctly configured with the necessary API host and auth details. + +Instructions: +- Run the tests using pytest: `pytest test_webhook.py` + +This test suite covers: +- Creating webhooks with valid and invalid data. +- Testing different authentication scenarios. +- Validating response schemas against the OpenAPI specification. +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'webhook.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['name'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_webhook_success(api_client, config_test_data, scenario_case): + """ + Test creating a webhook with valid data. + """ + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Prepare request payload + payload = { + "name": test_data["name"], + "events": test_data["events"], + "url": test_data["url"], + "verify-tls": test_data["verify-tls"], + "signing-secret": test_data["signing-secret"], + "scope": test_data["scope"] + } + + # Send POST request to create webhook + response = api_client.post('/webhook', json=payload) + + # Validate response status code + assert response.status_code == test_data["statusCode"] + + # Validate response schema + validation_result = validator.validate_schema_by_response( + '/webhook', 'post', str(response.status_code), response + ) + assert validation_result["valid"], validation_result.get("message", "") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_webhook_invalid_auth(api_client, scenario_case): + """ + Test creating a webhook with invalid authentication. + """ + # Prepare request payload + payload = { + "name": scenario_case["name"], + "events": scenario_case["events"], + "url": scenario_case["url"], + "verify-tls": scenario_case["verify-tls"], + "signing-secret": scenario_case["signing-secret"], + "scope": scenario_case["scope"] + } + + # Send POST request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.post('/webhook', json=payload, headers=headers) + + # Validate response status code is not 2xx + assert response.status_code != 201 + + # Validate response schema + validation_result = validator.validate_schema_by_response( + '/webhook', 'post', 'default', response + ) + assert validation_result["valid"], validation_result.get("message", "") + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_create_webhook_missing_auth(api_client, scenario_case): + """ + Test creating a webhook without authentication. + """ + # Prepare request payload + payload = { + "name": scenario_case["name"], + "events": scenario_case["events"], + "url": scenario_case["url"], + "verify-tls": scenario_case["verify-tls"], + "signing-secret": scenario_case["signing-secret"], + "scope": scenario_case["scope"] + } + + # Send POST request without auth + response = api_client.post('/webhook', json=payload, headers={}) + + # Validate response status code is not 2xx + assert response.status_code != 201 + + # Validate response schema + validation_result = validator.validate_schema_by_response( + '/webhook', 'post', 'default', response + ) + assert validation_result["valid"], validation_result.get("message", "") diff --git a/tests/CIRCLECI_API/test_webhook_webhook-id_delete.py b/tests/CIRCLECI_API/test_webhook_webhook-id_delete.py new file mode 100644 index 00000000..77a57e3b --- /dev/null +++ b/tests/CIRCLECI_API/test_webhook_webhook-id_delete.py @@ -0,0 +1,92 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /webhook/{webhook-id}_delete for http method type DELETE +# RoostTestHash=de1a400fa3 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the DELETE /webhook/{webhook-id} endpoint. + +Setup: +- Ensure `conftest.py` is in the same directory to provide necessary fixtures. +- Ensure `validator.py` is available for schema validation. +- Ensure `config.yml` is configured correctly with API host and authentication details. +- Ensure `webhook_webhook-id.json` is present in the same directory for test data. + +Run the tests using pytest: +$ pytest test_webhook.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Constants +API_SPEC_PATH = 'api.json' +TEST_DATA_FILENAME = 'webhook_webhook-id.json' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_webhook(api_client, config_test_data, scenario_case): + """ + Test DELETE /webhook/{webhook-id} endpoint with various scenarios. + """ + # Initialize SwaggerSchemaValidator + validator = SwaggerSchemaValidator(API_SPEC_PATH) + + # Prepare endpoint and headers + webhook_id = scenario_case.get('webhook-id', config_test_data['webhook-id']) + endpoint = f"/webhook/{webhook_id}" + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + # Make DELETE request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_delete_webhook_invalid_auth(api_client, scenario_case): + """ + Test DELETE /webhook/{webhook-id} endpoint with invalid authentication. + """ + # Initialize SwaggerSchemaValidator + validator = SwaggerSchemaValidator(API_SPEC_PATH) + + # Prepare endpoint and headers + webhook_id = scenario_case.get('webhook-id', 'invalidWebhook') + endpoint = f"/webhook/{webhook_id}" + headers = {'Authorization': 'Bearer invalid_token'} + + # Make DELETE request + response = api_client.delete(endpoint, headers=headers) + + # Validate response status code + assert response.status_code != 200, "Expected non-200 status code for invalid auth" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'DELETE', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_webhook_webhook-id_get.py b/tests/CIRCLECI_API/test_webhook_webhook-id_get.py new file mode 100644 index 00000000..125ef00f --- /dev/null +++ b/tests/CIRCLECI_API/test_webhook_webhook-id_get.py @@ -0,0 +1,72 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /webhook/{webhook-id}_get for http method type GET +# RoostTestHash=04eed72dbb +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'webhook_webhook-id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"webhook-id-{case['webhook-id']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_webhook_by_id(api_client, config_test_data, scenario_case): + """ + Test the GET /webhook/{webhook-id} endpoint. + """ + # Prepare endpoint and headers + webhook_id = scenario_case['webhook-id'] + endpoint = f"webhook/{webhook_id}" + + # Validate request schema + request_data = {"webhook-id": webhook_id} + validator.validate_json(request_data, "Webhook") + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', str(response.status_code), response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_webhook_by_id_invalid_auth(api_client, scenario_case): + """ + Test the GET /webhook/{webhook-id} endpoint with invalid authentication. + """ + # Prepare endpoint and headers + webhook_id = scenario_case['webhook-id'] + endpoint = f"webhook/{webhook_id}" + headers = {'Authorization': 'Bearer invalid_token'} + + # Make API request + response = api_client.make_request(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'GET', 'default', response) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_webhook_webhook-id_put.py b/tests/CIRCLECI_API/test_webhook_webhook-id_put.py new file mode 100644 index 00000000..8955a25e --- /dev/null +++ b/tests/CIRCLECI_API/test_webhook_webhook-id_put.py @@ -0,0 +1,111 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /webhook/{webhook-id}_put for http method type PUT +# RoostTestHash=35fba1f584 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the updateWebhook API endpoint. + +Setup: +- Ensure `conftest.py` and `validator.py` are in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. +- Place `webhook_webhook-id.json` in the same directory for test data. + +Run the tests using the command: pytest .py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI spec for validation +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'webhook_webhook-id.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_TEST_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_TEST_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_TEST_DATA))] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_webhook(api_client, config_test_data, scenario_case): + """ + Test the updateWebhook endpoint with various scenarios. + + Args: + api_client: Fixture providing an authenticated API client. + config_test_data: Fixture providing default test data. + scenario_case: Test data for a specific scenario. + """ + # Merge default test data with scenario-specific data + test_data = {**config_test_data, **scenario_case} + + # Construct the endpoint + endpoint = f"/webhook/{test_data['webhook-id']}" + + # Prepare request payload + payload = { + "name": test_data["name"], + "events": test_data["events"], + "url": test_data["url"], + "signing-secret": test_data["signing-secret"], + "verify-tls": test_data["verify-tls"] + } + + # Validate request payload + request_validation = validator.validate_json(payload, "Webhook") + assert request_validation["valid"], f"Request validation failed: {request_validation['message']}" + + # Make the API request + response = api_client.put(endpoint, json=payload) + + # Validate response status code + expected_status_code = test_data["statusCode"] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, "PUT", str(response.status_code), response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_update_webhook_invalid_auth(api_client, scenario_case): + """ + Test the updateWebhook endpoint with invalid authentication. + + Args: + api_client: Fixture providing an API client. + scenario_case: Test data for a specific scenario. + """ + # Construct the endpoint + endpoint = f"/webhook/{scenario_case['webhook-id']}" + + # Prepare request payload + payload = { + "name": scenario_case["name"], + "events": scenario_case["events"], + "url": scenario_case["url"], + "signing-secret": scenario_case["signing-secret"], + "verify-tls": scenario_case["verify-tls"] + } + + # Make the API request with invalid auth + headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.put(endpoint, json=payload, headers=headers) + + # Validate response status code for unauthorized access + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema for error + response_validation = validator.validate_schema_by_response(endpoint, "PUT", "default", response) + assert response_validation["valid"], f"Response validation failed: {response_validation['message']}" diff --git a/tests/CIRCLECI_API/test_workflow_id_approve_approval_request_id_post.py b/tests/CIRCLECI_API/test_workflow_id_approve_approval_request_id_post.py new file mode 100644 index 00000000..90f71693 --- /dev/null +++ b/tests/CIRCLECI_API/test_workflow_id_approve_approval_request_id_post.py @@ -0,0 +1,83 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /workflow/{id}/approve/{approval_request_id}_post for http method type POST +# RoostTestHash=ac9adbd240 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Load the OpenAPI specification +api_spec_path = Path(__file__).resolve().parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'workflow_id_approve_approval_request_id.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"{case['scenario']}" for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_approve_pending_approval_job(api_client, config_test_data, scenario_case): + """ + Test the /workflow/{id}/approve/{approval_request_id} endpoint. + """ + # Extract test data + approval_request_id = scenario_case.get('approval_request_id') + workflow_id = scenario_case.get('id') + expected_status_code = scenario_case.get('statusCode') + + # Construct endpoint + endpoint = f"/workflow/{workflow_id}/approve/{approval_request_id}" + + # Validate request schema + request_data = {} # No request body for this endpoint + validator.validate_json(request_data, "MessageResponse") + + # Make API request + response = api_client.post(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_approve_pending_approval_job_invalid_auth(api_client, scenario_case): + """ + Test the /workflow/{id}/approve/{approval_request_id} endpoint with invalid authentication. + """ + # Extract test data + approval_request_id = scenario_case.get('approval_request_id') + workflow_id = scenario_case.get('id') + + # Construct endpoint + endpoint = f"/workflow/{workflow_id}/approve/{approval_request_id}" + + # Make API request with invalid token + invalid_headers = {'Authorization': 'Bearer invalid_token'} + response = api_client.session.post(f"{api_client.host}/{endpoint.lstrip('/')}", headers=invalid_headers) + + # Validate response status code + assert response.status_code == 401, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response(endpoint, 'POST', 'default', response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_workflow_id_cancel_post.py b/tests/CIRCLECI_API/test_workflow_id_cancel_post.py new file mode 100644 index 00000000..4083b4d9 --- /dev/null +++ b/tests/CIRCLECI_API/test_workflow_id_cancel_post.py @@ -0,0 +1,97 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /workflow/{id}/cancel_post for http method type POST +# RoostTestHash=63440f5361 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for the /workflow/{id}/cancel endpoint. + +Setup: +- Ensure the `conftest.py` and `validator.py` are in the same directory. +- Place `workflow_id_cancel.json` in the same directory as this test file. +- Update `config.yml` with appropriate values for API host and authentication. + +Run the tests using the command: +pytest .py +""" + +import pytest +from pathlib import Path +import json +from validator import SwaggerSchemaValidator + +# Constants +TEST_DATA_FILENAME = 'workflow_id_cancel.json' +API_SPEC_PATH = 'api.json' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(filepath): + with open(filepath, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i['scenario']}" for i in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_workflow(api_client, config_test_data, scenario_case): + """ + Test the /workflow/{id}/cancel endpoint for various scenarios. + """ + # Load validator + validator = SwaggerSchemaValidator(API_SPEC_PATH) + + # Prepare endpoint and headers + endpoint = f"/workflow/{scenario_case['id']}/cancel" + headers = {'Authorization': f"Bearer {api_client.auth['api_key_header']}"} + + # Execute request + response = api_client.post(endpoint, headers=headers) + + # Validate response status code + assert response.status_code == scenario_case['statusCode'], \ + f"Expected {scenario_case['statusCode']}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=endpoint, + method='POST', + status_code=str(response.status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_cancel_workflow_invalid_auth(api_client, scenario_case): + """ + Test the /workflow/{id}/cancel endpoint with invalid authentication. + """ + # Prepare endpoint and headers + endpoint = f"/workflow/{scenario_case['id']}/cancel" + headers = {'Authorization': 'Bearer invalid_token'} + + # Execute request + response = api_client.post(endpoint, headers=headers) + + # Validate response status code for unauthorized access + assert response.status_code == 401, f"Expected 401, got {response.status_code}" + + # Validate response schema + validator = SwaggerSchemaValidator(API_SPEC_PATH) + validation_result = validator.validate_schema_by_response( + endpoint=endpoint, + method='POST', + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_workflow_id_get.py b/tests/CIRCLECI_API/test_workflow_id_get.py new file mode 100644 index 00000000..fe68e4a8 --- /dev/null +++ b/tests/CIRCLECI_API/test_workflow_id_get.py @@ -0,0 +1,83 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /workflow/{id}_get for http method type GET +# RoostTestHash=4d2ac9ff32 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +API_SPEC_PATH = Path(__file__).parent / 'api.json' +swagger_validator = SwaggerSchemaValidator(API_SPEC_PATH) + +# Load test data from JSON file +TEST_DATA_FILENAME = 'workflow_id.json' +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME + +def _load_json_file(path): + with open(path, 'r') as file: + return json.load(file) + +_ENDPOINT_DATA = _load_json_file(_endpoint_data_path) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [case['scenario'] for case in _ENDPOINT_DATA] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_workflow_by_id(api_client, config_test_data, scenario_case): + """ + Test the GET /workflow/{id} endpoint with various scenarios. + """ + # Extract test data + workflow_id = scenario_case.get('id', config_test_data['id']) + expected_status_code = scenario_case['statusCode'] + + # Construct endpoint + endpoint = f"/workflow/{workflow_id}" + + # Validate request schema + request_data = {"id": workflow_id} + validation_result = swagger_validator.validate_json(request_data, "Workflow") + assert validation_result['valid'], f"Request validation failed: {validation_result.get('message')}" + + # Make API request + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_workflow_by_id_invalid_auth(api_client, scenario_case): + """ + Test the GET /workflow/{id} endpoint with invalid authentication. + """ + # Extract test data + workflow_id = scenario_case.get('id', 'invalid-id') + expected_status_code = 401 # Unauthorized + + # Construct endpoint + endpoint = f"/workflow/{workflow_id}" + + # Make API request with invalid auth + response = api_client.get(endpoint, headers={'Authorization': 'Bearer invalid_token'}) + + # Validate response status code + assert response.status_code == expected_status_code, f"Unexpected status code: {response.status_code}" + + # Validate response schema + validation_result = swagger_validator.validate_schema_by_response(endpoint, 'GET', str(expected_status_code), response) + assert validation_result['valid'], f"Response validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_workflow_id_job_get.py b/tests/CIRCLECI_API/test_workflow_id_job_get.py new file mode 100644 index 00000000..126b1aa5 --- /dev/null +++ b/tests/CIRCLECI_API/test_workflow_id_job_get.py @@ -0,0 +1,91 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /workflow/{id}/job_get for http method type GET +# RoostTestHash=c035ff97c4 +# +# + +# ********RoostGPT******** +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator +from conftest import api_client, config_test_data + +# Load the OpenAPI specification +api_spec_path = Path(__file__).parent / 'api.json' +validator = SwaggerSchemaValidator(api_spec_path) + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / 'workflow_id_job.json' +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i, _ in enumerate(_ENDPOINT_DATA)] + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_workflow_jobs(api_client, config_test_data, scenario_case): + """ + Test the /workflow/{id}/job endpoint for various scenarios. + """ + # Setup + endpoint = f"workflow/{scenario_case['id']}/job" + expected_status_code = scenario_case['statusCode'] + + # Execute + response = api_client.get(endpoint) + + # Validate response status code + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/workflow/{{id}}/job", + method="GET", + status_code=str(expected_status_code), + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" + + # Additional response validation + if expected_status_code == 200: + response_data = response.json() + assert 'items' in response_data, "Response missing 'items'" + assert isinstance(response_data['items'], list), "'items' should be a list" + for item in response_data['items']: + assert 'id' in item, "Job item missing 'id'" + assert 'name' in item, "Job item missing 'name'" + assert 'started_at' in item, "Job item missing 'started_at'" + assert 'dependencies' in item, "Job item missing 'dependencies'" + assert 'project_slug' in item, "Job item missing 'project_slug'" + assert 'status' in item, "Job item missing 'status'" + assert 'type' in item, "Job item missing 'type'" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_get_workflow_jobs_invalid_auth(api_client, scenario_case): + """ + Test the /workflow/{id}/job endpoint with invalid authentication. + """ + # Setup + endpoint = f"workflow/{scenario_case['id']}/job" + headers = {'Authorization': 'Bearer invalid_token'} + + # Execute + response = api_client.get(endpoint, headers=headers) + + # Validate response status code + assert response.status_code != 200, "Expected non-200 status code for invalid auth" + + # Validate response schema + validation_result = validator.validate_schema_by_response( + endpoint=f"/workflow/{{id}}/job", + method="GET", + status_code='default', + response=response + ) + assert validation_result['valid'], f"Schema validation failed: {validation_result.get('message')}" diff --git a/tests/CIRCLECI_API/test_workflow_id_rerun_post.py b/tests/CIRCLECI_API/test_workflow_id_rerun_post.py new file mode 100644 index 00000000..b1c15708 --- /dev/null +++ b/tests/CIRCLECI_API/test_workflow_id_rerun_post.py @@ -0,0 +1,104 @@ +# ********RoostGPT******** + +# Test generated by RoostGPT for test testTimedout using AI Type Open AI and AI Model gpt-4o +# +# Test file generated for /workflow/{id}/rerun_post for http method type POST +# RoostTestHash=9e965eff68 +# +# + +# ********RoostGPT******** +""" +Pytest test suite for testing the /workflow/{id}/rerun API endpoint. + +Setup: +- Ensure the `conftest.py` and `validator.py` are in the same directory. +- Ensure `config.yml` is configured with the correct API host and authentication details. +- Place `workflow_id_rerun.json` in the same directory as this test file. + +Run the tests using pytest: +$ pytest test_rerun_workflow.py +""" + +import pytest +import json +from pathlib import Path +from validator import SwaggerSchemaValidator + +# Constants +TEST_DATA_FILENAME = 'workflow_id_rerun.json' +API_SPEC_PATH = 'api.json' + +# Load test data +_here = Path(__file__).resolve().parent +_endpoint_data_path = _here / TEST_DATA_FILENAME +with open(_endpoint_data_path, 'r') as f: + _ENDPOINT_DATA = json.load(f) + +# Reusable parametrize args +_PARAM_CASES = _ENDPOINT_DATA +_PARAM_IDS = [f"scenario_{i}" for i in range(len(_ENDPOINT_DATA))] + +# Initialize SwaggerSchemaValidator +validator = SwaggerSchemaValidator(API_SPEC_PATH) + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_rerun_workflow(api_client, config_test_data, scenario_case): + """ + Test the /workflow/{id}/rerun endpoint with various scenarios. + """ + # Setup + endpoint = f"workflow/{scenario_case['id']}/rerun" + headers = {'Content-Type': 'application/json'} + payload = {} + + # Populate payload with optional fields if present + if 'enable_ssh' in scenario_case: + payload['enable_ssh'] = scenario_case['enable_ssh'] + if 'from_failed' in scenario_case: + payload['from_failed'] = scenario_case['from_failed'] + if 'jobs' in scenario_case: + payload['jobs'] = scenario_case['jobs'] + if 'sparse_tree' in scenario_case: + payload['sparse_tree'] = scenario_case['sparse_tree'] + + # Validate request schema + request_validation = validator.validate_json(payload, 'RerunWorkflowParameters') + assert request_validation['valid'], f"Request validation failed: {request_validation.get('message')}" + + # Make API request + response = api_client.post(endpoint, headers=headers, json=payload) + + # Validate response status code + expected_status_code = scenario_case['statusCode'] + assert response.status_code == expected_status_code, f"Expected {expected_status_code}, got {response.status_code}" + + # Validate response schema + response_validation = validator.validate_schema_by_response(endpoint, 'POST', str(response.status_code), response) + assert response_validation['valid'], f"Response validation failed: {response_validation.get('message')}" + +@pytest.mark.parametrize("scenario_case", _PARAM_CASES, ids=_PARAM_IDS) +def test_rerun_workflow_invalid_auth(api_client, scenario_case): + """ + Test the /workflow/{id}/rerun endpoint with invalid authentication. + """ + # Setup + endpoint = f"workflow/{scenario_case['id']}/rerun" + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer invalid_token'} + payload = {} + + # Populate payload with optional fields if present + if 'enable_ssh' in scenario_case: + payload['enable_ssh'] = scenario_case['enable_ssh'] + if 'from_failed' in scenario_case: + payload['from_failed'] = scenario_case['from_failed'] + if 'jobs' in scenario_case: + payload['jobs'] = scenario_case['jobs'] + if 'sparse_tree' in scenario_case: + payload['sparse_tree'] = scenario_case['sparse_tree'] + + # Make API request + response = api_client.post(endpoint, headers=headers, json=payload) + + # Validate response status code is not 2xx + assert response.status_code != 202, f"Expected non-2xx status code, got {response.status_code}" diff --git a/tests/CIRCLECI_API/user_id.json b/tests/CIRCLECI_API/user_id.json new file mode 100644 index 00000000..04c69342 --- /dev/null +++ b/tests/CIRCLECI_API/user_id.json @@ -0,0 +1,26 @@ +[ + { + "id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "123e4567-e89b-12d3-a456-426614174001", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "nonexistent-id", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/validator.py b/tests/CIRCLECI_API/validator.py new file mode 100644 index 00000000..70311dc7 --- /dev/null +++ b/tests/CIRCLECI_API/validator.py @@ -0,0 +1,225 @@ + +import json +import yaml +from jsonschema import ( + Draft202012Validator, + Draft7Validator, + Draft4Validator, + ValidationError, +) +from referencing import Registry, Resource +from typing import Dict, Any +import requests + + +class SwaggerSchemaValidator: + """ + Validates JSON, XML, and text responses + """ + + def __init__(self, swagger_source: str): + self.spec = self._load_spec(swagger_source) + self.is_swagger2 = False + self.schemas = self._extract_schemas() + self.registry = Registry() + + for name, schema in self.schemas.items(): + pointer = ( + f"#/definitions/{name}" if self.is_swagger2 + else f"#/components/schemas/{name}" + ) + + wrapped = { + "$schema": "https://json-schema.org/draft/2020-12/schema", + **schema, + } + self.registry = self.registry.with_resource( + pointer, + Resource.from_contents(wrapped) + ) + + def _load_spec(self, source: str) -> Dict[str, Any]: + # Convert Path to string if needed + if isinstance(source, Path): + source = str(source) + + if source.startswith(("http://", "https://")): + resp = requests.get(source) + resp.raise_for_status() + text = resp.text + + try: + return yaml.safe_load(text) + except yaml.YAMLError: + try: + return json.loads(text) + except json.JSONDecodeError: + raise ValueError("URL does not contain valid YAML or JSON") + + with open(source, "r") as f: + text = f.read() + + if source.endswith((".yaml", ".yml")): + return yaml.safe_load(text) + if source.endswith(".json"): + return json.loads(text) + + raise ValueError("File must be YAML or JSON") + + def _extract_schemas(self): + if "components" in self.spec and "schemas" in self.spec["components"]: + self.is_swagger2 = False + return self.spec["components"]["schemas"] + + if "definitions" in self.spec: + self.is_swagger2 = True + return self.spec["definitions"] + + raise ValueError("No schemas found under components/schemas or definitions") + + def get_version(self): + return self.spec.get("openapi") or self.spec.get("swagger") or "" + + def select_validator(self): + v = self.get_version() + + if v.startswith("2."): + return Draft4Validator + if v.startswith("3.0"): + return Draft7Validator + if v.startswith("3.1"): + return Draft202012Validator + + return Draft202012Validator + + def resolve_ref(self, ref): + if ref.startswith("#/"): + parts = ref.lstrip("#/").split("/") + node = self.spec + for p in parts: + node = node[p] + return node + + raise ValueError(f"External refs not supported: {ref}") + + def deref(self, schema): + if isinstance(schema, dict): + if "$ref" in schema: + resolved = self.resolve_ref(schema["$ref"]) + return self.deref(resolved) + return {k: self.deref(v) for k, v in schema.items()} + + if isinstance(schema, list): + return [self.deref(v) for v in schema] + + return schema + + def detect_format(self, response): + ctype = response.headers.get("Content-Type", "").lower() + if "json" in ctype: + return "json" + if "xml" in ctype: + return "xml" + if "text" in ctype: + return "text" + return "binary" + + def parse_body(self, response, fmt): + if fmt == "json": + return json.loads(response.text) + + if fmt == "xml": + import xmltodict + return xmltodict.parse(response.text) + + if fmt == "text": + return response.text + + return response.content + + def extract_schema_for_media_type(self, response_block, content_type): + content = response_block.get("content", {}) + + if content_type in content: + return content[content_type].get("schema") + + if "json" in content_type: + for k, v in content.items(): + if k == "application/json" or k.endswith("+json"): + return v.get("schema") + + if "xml" in content_type: + for k, v in content.items(): + if "xml" in k: + return v.get("schema") + + if "text/plain" in content: + return content["text/plain"].get("schema") + + return None + + + def validate_json(self, data, schema_name): + if schema_name not in self.schemas: + raise ValueError(f"Schema '{schema_name}' not found") + + schema = self.deref(self.schemas[schema_name]) + validator_cls = self.select_validator() + validator = validator_cls(schema, registry=self.registry) + + try: + validator.validate(data) + return {"valid": True} + except ValidationError as e: + return { + "valid": False, + "message": e.message, + "path": list(e.path), + "schema_path": list(e.schema_path), + } + + def validate_schema_by_response(self, endpoint, method, status_code, response): + fmt = self.detect_format(response) + + paths = self.spec.get("paths", {}) + op = paths.get(endpoint, {}).get(method.lower()) + + if not op: + return {"valid": False, "message": f"Method {method} not found at path {endpoint}"} + + responses = op.get("responses", {}) + response_block = responses.get(status_code) + + if not response_block: + return {"valid": False, "message": f"No response block for {status_code}"} + + ctype = response.headers.get("Content-Type", "").split(";")[0].strip() + + if "content" in response_block: + schema = self.extract_schema_for_media_type(response_block, ctype) + else: + schema = response_block.get("schema") + + if schema is None: + return {"valid": True, "message": "No schema defined for this content type"} + + try: + data = self.parse_body(response, fmt) + except Exception as e: + return {"valid": False, "message": f"Body parsing failed: {e}"} + + schema = self.deref(schema) + + validator_cls = self.select_validator() + validator = validator_cls(schema, registry=self.registry) + + try: + validator.validate(data) + return {"valid": True} + except ValidationError as e: + return { + "valid": False, + "message": e.message, + "path": list(e.path), + "schema_path": list(e.schema_path), + } diff --git a/tests/CIRCLECI_API/webhook.json b/tests/CIRCLECI_API/webhook.json new file mode 100644 index 00000000..72fb7a60 --- /dev/null +++ b/tests/CIRCLECI_API/webhook.json @@ -0,0 +1,31 @@ +[ + { + "scope-id": "123e4567-e89b-12d3-a456-426614174000", + "scope-type": "project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "scope-id": "123e4567-e89b-12d3-a456-426614174000", + "scope-type": "project", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "scope-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "scope-id": "invalid-uuid", + "scope-type": "project", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "scope-id": "123e4567-e89b-12d3-a456-426614174000", + "scope-type": "invalid-type", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/webhook_webhook-id.json b/tests/CIRCLECI_API/webhook_webhook-id.json new file mode 100644 index 00000000..f73795ac --- /dev/null +++ b/tests/CIRCLECI_API/webhook_webhook-id.json @@ -0,0 +1,27 @@ +[ + { + "webhook-id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "webhook-id": "123e4567-e89b-12d3-a456-426614174001", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "webhook-id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "webhook-id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "webhook-id": "123e4567-e89b-12d3-a456-426614174002", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/workflow_id.json b/tests/CIRCLECI_API/workflow_id.json new file mode 100644 index 00000000..9c6a7e72 --- /dev/null +++ b/tests/CIRCLECI_API/workflow_id.json @@ -0,0 +1,27 @@ +[ + { + "id": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "5034460f-c7c4-4c43-9457-de07e2029e7b", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "123", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/workflow_id_approve_approval_request_id.json b/tests/CIRCLECI_API/workflow_id_approve_approval_request_id.json new file mode 100644 index 00000000..3447e3be --- /dev/null +++ b/tests/CIRCLECI_API/workflow_id_approve_approval_request_id.json @@ -0,0 +1,32 @@ +[ + { + "approval_request_id": "12345", + "id": "workflow_001", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "approval_request_id": "67890", + "id": "workflow_002", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "approval_request_id": "", + "id": "workflow_003", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "approval_request_id": "invalid_id", + "id": "workflow_004", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "approval_request_id": "12345", + "id": "", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/workflow_id_cancel.json b/tests/CIRCLECI_API/workflow_id_cancel.json new file mode 100644 index 00000000..2e114b7c --- /dev/null +++ b/tests/CIRCLECI_API/workflow_id_cancel.json @@ -0,0 +1,27 @@ +[ + { + "id": "valid_workflow_id_123", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "id": "valid_workflow_id_456", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "id": "", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "invalid_workflow_id_789", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "nonexistent_workflow_id_000", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/workflow_id_job.json b/tests/CIRCLECI_API/workflow_id_job.json new file mode 100644 index 00000000..756e1f95 --- /dev/null +++ b/tests/CIRCLECI_API/workflow_id_job.json @@ -0,0 +1,26 @@ +[ + { + "id": "123e4567-e89b-12d3-a456-426614174000", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "id": "123e4567-e89b-12d3-a456-426614174001", + "statusCode": 200, + "scenario": "Successful responses: OK" + }, + { + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "invalid-uuid", + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "nonexistent-id", + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file diff --git a/tests/CIRCLECI_API/workflow_id_rerun.json b/tests/CIRCLECI_API/workflow_id_rerun.json new file mode 100644 index 00000000..febe99b5 --- /dev/null +++ b/tests/CIRCLECI_API/workflow_id_rerun.json @@ -0,0 +1,54 @@ +[ + { + "id": "0e53027b-521a-4c40-9042-47e72b3c63a3", + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "id": "0e53027b-521a-4c40-9042-47e72b3c63a3", + "enable_ssh": true, + "from_failed": false, + "jobs": [ + "job1", + "job2" + ], + "sparse_tree": true, + "statusCode": 202, + "scenario": "Successful responses: Accepted" + }, + { + "enable_ssh": true, + "from_failed": false, + "jobs": [ + "job1", + "job2" + ], + "sparse_tree": true, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "invalid-uuid", + "enable_ssh": true, + "from_failed": false, + "jobs": [ + "job1", + "job2" + ], + "sparse_tree": true, + "statusCode": "default", + "scenario": "Unknown response class" + }, + { + "id": "0e53027b-521a-4c40-9042-47e72b3c63a3", + "enable_ssh": "yes", + "from_failed": false, + "jobs": [ + "job1", + "job2" + ], + "sparse_tree": true, + "statusCode": "default", + "scenario": "Unknown response class" + } +] \ No newline at end of file